Compare commits
	
		
			6 Commits
		
	
	
		
			3a51707280
			...
			166bc6fc6d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 166bc6fc6d | |||
| bf4207ba8c | |||
| 78080b4682 | |||
| 9159270e87 | |||
| 428eff1468 | |||
| 5ec8d4b0a5 | 
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -6,6 +6,9 @@
 | 
				
			|||||||
**/*.log
 | 
					**/*.log
 | 
				
			||||||
**/*.bin
 | 
					**/*.bin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build on WIndows
 | 
					# Build on Windows
 | 
				
			||||||
/.build_config
 | 
					/.build_config
 | 
				
			||||||
/lib/SDL2
 | 
					/lib/SDL2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Any Custom Scripts for Debugging purposes
 | 
				
			||||||
 | 
					*.sh
 | 
				
			||||||
@@ -7,8 +7,11 @@ buf: []u8,
 | 
				
			|||||||
alloc: Allocator,
 | 
					alloc: Allocator,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init(alloc: Allocator) !Self {
 | 
					pub fn init(alloc: Allocator) !Self {
 | 
				
			||||||
 | 
					    const buf = try alloc.alloc(u8, 0x8000);
 | 
				
			||||||
 | 
					    std.mem.set(u8, buf, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Self{
 | 
					    return Self{
 | 
				
			||||||
        .buf = try alloc.alloc(u8, 0x8000),
 | 
					        .buf = buf,
 | 
				
			||||||
        .alloc = alloc,
 | 
					        .alloc = alloc,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,11 @@ buf: []u8,
 | 
				
			|||||||
alloc: Allocator,
 | 
					alloc: Allocator,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init(alloc: Allocator) !Self {
 | 
					pub fn init(alloc: Allocator) !Self {
 | 
				
			||||||
 | 
					    const buf = try alloc.alloc(u8, 0x40000);
 | 
				
			||||||
 | 
					    std.mem.set(u8, buf, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Self{
 | 
					    return Self{
 | 
				
			||||||
        .buf = try alloc.alloc(u8, 0x40000),
 | 
					        .buf = buf,
 | 
				
			||||||
        .alloc = alloc,
 | 
					        .alloc = alloc,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,6 @@ pub const Io = struct {
 | 
				
			|||||||
            0x0400_0000 => @as(u32, self.dispcnt.raw),
 | 
					            0x0400_0000 => @as(u32, self.dispcnt.raw),
 | 
				
			||||||
            0x0400_0004 => @as(u32, self.dispstat.raw),
 | 
					            0x0400_0004 => @as(u32, self.dispstat.raw),
 | 
				
			||||||
            0x0400_0006 => @as(u32, self.vcount.raw),
 | 
					            0x0400_0006 => @as(u32, self.vcount.raw),
 | 
				
			||||||
            0x0400_0130 => @as(u32, self.keyinput.raw),
 | 
					 | 
				
			||||||
            0x0400_0200 => @as(u32, self.ie.raw),
 | 
					            0x0400_0200 => @as(u32, self.ie.raw),
 | 
				
			||||||
            0x0400_0208 => @boolToInt(self.ime),
 | 
					            0x0400_0208 => @boolToInt(self.ime),
 | 
				
			||||||
            else => std.debug.panic("[I/O:32] tried to read from {X:}", .{addr}),
 | 
					            else => std.debug.panic("[I/O:32] tried to read from {X:}", .{addr}),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,26 +28,28 @@ pub fn format78(comptime op: u2, comptime T: bool) InstrFn {
 | 
				
			|||||||
            const address = cpu.r[rb] + cpu.r[ro];
 | 
					            const address = cpu.r[rb] + cpu.r[ro];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (T) {
 | 
					            if (T) {
 | 
				
			||||||
 | 
					                // Format 8
 | 
				
			||||||
                switch (op) {
 | 
					                switch (op) {
 | 
				
			||||||
                    0b00 => {
 | 
					                    0b00 => {
 | 
				
			||||||
                        // STRH
 | 
					                        // STRH
 | 
				
			||||||
                        bus.write16(address & 0xFFFF_FFFE, @truncate(u16, cpu.r[rd]));
 | 
					                        bus.write16(address & 0xFFFF_FFFE, @truncate(u16, cpu.r[rd]));
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    0b01 => {
 | 
					                    0b01 => {
 | 
				
			||||||
 | 
					                        // LDSB
 | 
				
			||||||
 | 
					                        cpu.r[rd] = u32SignExtend(8, @as(u32, bus.read8(address)));
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    0b10 => {
 | 
				
			||||||
                        // LDRH
 | 
					                        // LDRH
 | 
				
			||||||
                        const value = bus.read16(address & 0xFFFF_FFFE);
 | 
					                        const value = bus.read16(address & 0xFFFF_FFFE);
 | 
				
			||||||
                        cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1));
 | 
					                        cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1));
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    0b10 => {
 | 
					 | 
				
			||||||
                        // LDSB
 | 
					 | 
				
			||||||
                        cpu.r[rd] = u32SignExtend(8, @as(u32, bus.read8(address)));
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    0b11 => {
 | 
					                    0b11 => {
 | 
				
			||||||
                        // LDSH
 | 
					                        // LDSH
 | 
				
			||||||
                        cpu.r[rd] = u32SignExtend(16, @as(u32, bus.read16(address & 0xFFFF_FFFE)));
 | 
					                        cpu.r[rd] = u32SignExtend(16, @as(u32, bus.read16(address & 0xFFFF_FFFE)));
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Format 7
 | 
				
			||||||
                switch (op) {
 | 
					                switch (op) {
 | 
				
			||||||
                    0b00 => {
 | 
					                    0b00 => {
 | 
				
			||||||
                        // STR
 | 
					                        // STR
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ const File = std.fs.File;
 | 
				
			|||||||
const window_scale = 3;
 | 
					const window_scale = 3;
 | 
				
			||||||
const gba_width = @import("ppu.zig").width;
 | 
					const gba_width = @import("ppu.zig").width;
 | 
				
			||||||
const gba_height = @import("ppu.zig").height;
 | 
					const gba_height = @import("ppu.zig").height;
 | 
				
			||||||
const buf_pitch = @import("ppu.zig").buf_pitch;
 | 
					const framebuf_pitch = @import("ppu.zig").framebuf_pitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const enable_logging: bool = false;
 | 
					pub const enable_logging: bool = false;
 | 
				
			||||||
const is_binary: bool = false;
 | 
					const is_binary: bool = false;
 | 
				
			||||||
@@ -164,8 +164,8 @@ 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 = bus.ppu.frame_buf.ptr;
 | 
					        const buf_ptr = bus.ppu.framebuf.ptr;
 | 
				
			||||||
        _ = SDL.SDL_UpdateTexture(texture, null, buf_ptr, buf_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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								src/ppu.zig
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/ppu.zig
									
									
									
									
									
								
							@@ -7,8 +7,7 @@ const Scheduler = @import("scheduler.zig").Scheduler;
 | 
				
			|||||||
const Allocator = std.mem.Allocator;
 | 
					const Allocator = std.mem.Allocator;
 | 
				
			||||||
pub const width = 240;
 | 
					pub const width = 240;
 | 
				
			||||||
pub const height = 160;
 | 
					pub const height = 160;
 | 
				
			||||||
pub const buf_pitch = width * @sizeOf(u16);
 | 
					pub const framebuf_pitch = width * @sizeOf(u16);
 | 
				
			||||||
const buf_len = buf_pitch * height;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const Ppu = struct {
 | 
					pub const Ppu = struct {
 | 
				
			||||||
    const Self = @This();
 | 
					    const Self = @This();
 | 
				
			||||||
@@ -16,24 +15,27 @@ pub const Ppu = struct {
 | 
				
			|||||||
    vram: Vram,
 | 
					    vram: Vram,
 | 
				
			||||||
    palette: Palette,
 | 
					    palette: Palette,
 | 
				
			||||||
    sched: *Scheduler,
 | 
					    sched: *Scheduler,
 | 
				
			||||||
    frame_buf: []u8,
 | 
					    framebuf: []u8,
 | 
				
			||||||
    alloc: Allocator,
 | 
					    alloc: Allocator,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn init(alloc: Allocator, sched: *Scheduler) !Self {
 | 
					    pub fn init(alloc: Allocator, sched: *Scheduler) !Self {
 | 
				
			||||||
        // Queue first Hblank
 | 
					        // Queue first Hblank
 | 
				
			||||||
        sched.push(.Draw, sched.tick + (240 * 4));
 | 
					        sched.push(.Draw, sched.tick + (240 * 4));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const framebuf = try alloc.alloc(u8, framebuf_pitch * height);
 | 
				
			||||||
 | 
					        std.mem.set(u8, framebuf, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Self{
 | 
					        return Self{
 | 
				
			||||||
            .vram = try Vram.init(alloc),
 | 
					            .vram = try Vram.init(alloc),
 | 
				
			||||||
            .palette = try Palette.init(alloc),
 | 
					            .palette = try Palette.init(alloc),
 | 
				
			||||||
            .sched = sched,
 | 
					            .sched = sched,
 | 
				
			||||||
            .frame_buf = try alloc.alloc(u8, buf_len),
 | 
					            .framebuf = framebuf,
 | 
				
			||||||
            .alloc = alloc,
 | 
					            .alloc = alloc,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn deinit(self: Self) void {
 | 
					    pub fn deinit(self: Self) void {
 | 
				
			||||||
        self.alloc.free(self.frame_buf);
 | 
					        self.alloc.free(self.framebuf);
 | 
				
			||||||
        self.vram.deinit();
 | 
					        self.vram.deinit();
 | 
				
			||||||
        self.palette.deinit();
 | 
					        self.palette.deinit();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -44,10 +46,10 @@ pub const Ppu = struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        switch (bg_mode) {
 | 
					        switch (bg_mode) {
 | 
				
			||||||
            0x3 => {
 | 
					            0x3 => {
 | 
				
			||||||
                const start = buf_pitch * @as(usize, scanline);
 | 
					                const start = framebuf_pitch * @as(usize, scanline);
 | 
				
			||||||
                const end = start + buf_pitch;
 | 
					                const end = start + framebuf_pitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std.mem.copy(u8, self.frame_buf[start..end], self.vram.buf[start..end]);
 | 
					                std.mem.copy(u8, self.framebuf[start..end], self.vram.buf[start..end]);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            0x4 => {
 | 
					            0x4 => {
 | 
				
			||||||
                const select = io.dispcnt.frame_select.read();
 | 
					                const select = io.dispcnt.frame_select.read();
 | 
				
			||||||
@@ -62,8 +64,8 @@ pub const Ppu = struct {
 | 
				
			|||||||
                    const id = byte * 2;
 | 
					                    const id = byte * 2;
 | 
				
			||||||
                    const j = i * @sizeOf(u16);
 | 
					                    const j = i * @sizeOf(u16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    self.frame_buf[buf_start + j + 1] = self.palette.buf[id + 1];
 | 
					                    self.framebuf[buf_start + j + 1] = self.palette.buf[id + 1];
 | 
				
			||||||
                    self.frame_buf[buf_start + j] = self.palette.buf[id];
 | 
					                    self.framebuf[buf_start + j] = self.palette.buf[id];
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            else => {}, // std.debug.panic("[PPU] TODO: Implement BG Mode {}", .{bg_mode}),
 | 
					            else => {}, // std.debug.panic("[PPU] TODO: Implement BG Mode {}", .{bg_mode}),
 | 
				
			||||||
@@ -78,8 +80,11 @@ const Palette = struct {
 | 
				
			|||||||
    alloc: Allocator,
 | 
					    alloc: Allocator,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn init(alloc: Allocator) !Self {
 | 
					    fn init(alloc: Allocator) !Self {
 | 
				
			||||||
 | 
					        const buf = try alloc.alloc(u8, 0x400);
 | 
				
			||||||
 | 
					        std.mem.set(u8, buf, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Self{
 | 
					        return Self{
 | 
				
			||||||
            .buf = try alloc.alloc(u8, 0x400),
 | 
					            .buf = buf,
 | 
				
			||||||
            .alloc = alloc,
 | 
					            .alloc = alloc,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -118,13 +123,8 @@ const Vram = struct {
 | 
				
			|||||||
    alloc: Allocator,
 | 
					    alloc: Allocator,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn init(alloc: Allocator) !Self {
 | 
					    fn init(alloc: Allocator) !Self {
 | 
				
			||||||
        // In Modes 3 and 4, parts of the VRAM are copied to the
 | 
					 | 
				
			||||||
        // frame buffer, therefore we want to zero-initialize Vram
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // some programs like Armwrestler assume that VRAM is zeroed-out.
 | 
					 | 
				
			||||||
        const black = std.mem.zeroes([0x18000]u8);
 | 
					 | 
				
			||||||
        const buf = try alloc.alloc(u8, 0x18000);
 | 
					        const buf = try alloc.alloc(u8, 0x18000);
 | 
				
			||||||
        std.mem.copy(u8, buf, &black);
 | 
					        std.mem.set(u8, buf, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Self{
 | 
					        return Self{
 | 
				
			||||||
            .buf = buf,
 | 
					            .buf = buf,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/util.zig
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/util.zig
									
									
									
									
									
								
							@@ -1,6 +1,10 @@
 | 
				
			|||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn signExtend(comptime T: type, comptime bits: usize, value: anytype) T {
 | 
					pub fn u32SignExtend(comptime bits: usize, value: u32) u32 {
 | 
				
			||||||
 | 
					    return @bitCast(u32, signExtend(i32, bits, @bitCast(i32, value)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn signExtend(comptime T: type, comptime bits: usize, value: anytype) T {
 | 
				
			||||||
    const ValT = comptime @TypeOf(value);
 | 
					    const ValT = comptime @TypeOf(value);
 | 
				
			||||||
    comptime std.debug.assert(isInteger(ValT));
 | 
					    comptime std.debug.assert(isInteger(ValT));
 | 
				
			||||||
    comptime std.debug.assert(isSigned(ValT));
 | 
					    comptime std.debug.assert(isSigned(ValT));
 | 
				
			||||||
@@ -16,10 +20,6 @@ pub fn signExtend(comptime T: type, comptime bits: usize, value: anytype) T {
 | 
				
			|||||||
    return ((value & ((1 << bits) - 1)) << bit_diff) >> bit_diff;
 | 
					    return ((value & ((1 << bits) - 1)) << bit_diff) >> bit_diff;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn u32SignExtend(comptime bits: usize, value: u32) u32 {
 | 
					 | 
				
			||||||
    return @bitCast(u32, signExtend(i32, bits, @bitCast(i32, value)));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn isInteger(comptime T: type) bool {
 | 
					fn isInteger(comptime T: type) bool {
 | 
				
			||||||
    return @typeInfo(T) == .Int;
 | 
					    return @typeInfo(T) == .Int;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user