feat: Mode 0 MVP
This commit is contained in:
parent
338122ed43
commit
5835b509e4
63
src/ppu.zig
63
src/ppu.zig
|
@ -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,
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue