feat: Mode 0 MVP

This commit is contained in:
Rekai Nyangadzayi Musuka 2022-10-21 05:12:20 -03:00
parent 1b17b1eb0c
commit efc7d817db
1 changed files with 62 additions and 1 deletions

View File

@ -4,6 +4,9 @@ const io = @import("bus/io.zig");
const EventKind = @import("scheduler.zig").EventKind; const EventKind = @import("scheduler.zig").EventKind;
const Scheduler = @import("scheduler.zig").Scheduler; const Scheduler = @import("scheduler.zig").Scheduler;
const Bit = @import("bitfield").Bit;
const Bitfield = @import("bitfield").Bitfield;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
pub const width = 240; pub const width = 240;
@ -68,8 +71,50 @@ pub const Ppu = struct {
switch (bg_mode) { switch (bg_mode) {
0x0 => { 0x0 => {
// Mode 0 // A Tile is always 8x8 pixels
// Mode 0 Implementation Assuming:
// - Scrolling isn't a thing
// - Bill Gates said we'll never need more than BG0
// Write to this Scanline once we're done
const start = framebuf_pitch * @as(usize, scanline);
var scanline_buf = std.mem.zeroes([framebuf_pitch]u8);
// These we can probably move to top level?
const charblock_len: u32 = 0x4000;
const screenblock_len: u32 = 0x800;
const cbb: u2 = self.bg0.cnt.char_base.read(); // Char Block Base
const sbb: u5 = self.bg0.cnt.screen_base.read(); // Screen Block Base
const is_8bpp: bool = self.bg0.cnt.palette_type.read(); // Colour Mode
const size: u2 = self.bg0.cnt.screen_size.read(); // Background Size
// 0x0600_000 is implied because we can access VRAM without the Bus
const char_base: u32 = charblock_len * @as(u32, cbb);
const screen_base: u32 = screenblock_len * @as(u32, sbb);
const y = @as(u32, scanline);
var x: u32 = 0;
while (x < width) : (x += 1) {
const entry_addr = screen_base + tilemapIndex(size, x, y);
const entry = @bitCast(ScreenEntry, @as(u16, self.vram.buf[entry_addr + 1]) << 8 | @as(u16, self.vram.buf[entry_addr]));
const tile_id: u32 = entry.tile_id.read();
const px_y = if (entry.h_flip.read()) 7 - (y % 8) else y % 8;
const px_x = if (entry.v_flip.read()) 7 - (x % 8) else x % 8;
const tile_addr = char_base + if (is_8bpp) 0x40 * tile_id + 0x8 * px_y else 0x20 * tile_id + 0x4 * px_y;
var tile = self.vram.buf[tile_addr + if (is_8bpp) px_x else px_x >> 1];
tile = if (px_x & 1 == 1) tile >> 4 else tile & 0xF;
const pal_bank: u8 = @as(u8, entry.palette_bank.read()) << 4;
const colour = pal_bank | tile;
std.mem.copy(u8, scanline_buf[x * 2 ..][0..2], self.palette.buf[colour * 2 ..][0..2]);
}
std.mem.copy(u8, self.framebuf[start..][0..framebuf_pitch], &scanline_buf);
}, },
0x3 => { 0x3 => {
const start = framebuf_pitch * @as(usize, scanline); const start = framebuf_pitch * @as(usize, scanline);
@ -94,6 +139,14 @@ pub const Ppu = struct {
else => std.debug.panic("[PPU] TODO: Implement BG Mode {}", .{bg_mode}), else => std.debug.panic("[PPU] TODO: Implement BG Mode {}", .{bg_mode}),
} }
} }
fn tilemapIndex(size: u2, x: u32, y: u32) u32 {
return switch (size) {
0 => (((y % 256) / 8) * 64) + (((x % 256) / 8) * 2),
1 => (((y % 256) / 8) * 64) + (((x % 256) / 8) * 2),
else => std.debug.panic("tile size {}", .{size}),
};
}
}; };
const Palette = struct { const Palette = struct {
@ -241,3 +294,11 @@ const Background = struct {
}; };
} }
}; };
const ScreenEntry = extern union {
tile_id: Bitfield(u16, 0, 10),
h_flip: Bit(u16, 10),
v_flip: Bit(u16, 11),
palette_bank: Bitfield(u16, 12, 4),
raw: u16,
};