Compare commits

..

6 Commits

9 changed files with 45 additions and 34 deletions

7
.gitignore vendored
View File

@ -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

1
README.md Normal file
View File

@ -0,0 +1 @@
Built using Zig v0.10.0-dev.548+4ca9a8d19

View File

@ -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,
}; };
} }

View File

@ -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,
}; };
} }

View File

@ -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}),

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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;
} }