Compare commits

..

3 Commits

2 changed files with 91 additions and 69 deletions

View File

@ -142,6 +142,14 @@ pub fn read32(bus: *const Bus, addr: u32) u32 {
pub fn write32(bus: *Bus, addr: u32, word: u32) void { pub fn write32(bus: *Bus, addr: u32, word: u32) void {
switch (addr) { switch (addr) {
0x0400_0000 => bus.ppu.dispcnt.raw = @truncate(u16, word), 0x0400_0000 => bus.ppu.dispcnt.raw = @truncate(u16, word),
0x0400_0010 => bus.ppu.bg[0].hofs.raw = @truncate(u16, word), // TODO: Don't write out every HOFS / VOFS?
0x0400_0012 => bus.ppu.bg[0].vofs.raw = @truncate(u16, word),
0x0400_0014 => bus.ppu.bg[1].hofs.raw = @truncate(u16, word),
0x0400_0016 => bus.ppu.bg[1].vofs.raw = @truncate(u16, word),
0x0400_0018 => bus.ppu.bg[2].hofs.raw = @truncate(u16, word),
0x0400_001A => bus.ppu.bg[2].vofs.raw = @truncate(u16, word),
0x0400_001C => bus.ppu.bg[3].hofs.raw = @truncate(u16, word),
0x0400_001E => bus.ppu.bg[3].vofs.raw = @truncate(u16, word),
0x0400_0200 => bus.io.ie.raw = @truncate(u16, word), 0x0400_0200 => bus.io.ie.raw = @truncate(u16, word),
0x0400_0208 => bus.io.ime = word & 1 == 1, 0x0400_0208 => bus.io.ime = word & 1 == 1,
else => std.debug.panic("[I/O:32] tried to write 0x{X:} to 0x{X:}", .{ word, addr }), else => std.debug.panic("[I/O:32] tried to write 0x{X:} to 0x{X:}", .{ word, addr }),
@ -164,9 +172,15 @@ pub fn write16(bus: *Bus, addr: u32, halfword: u16) void {
switch (addr) { switch (addr) {
0x0400_0000 => bus.ppu.dispcnt.raw = halfword, 0x0400_0000 => bus.ppu.dispcnt.raw = halfword,
0x0400_0004 => bus.ppu.dispstat.raw = halfword, 0x0400_0004 => bus.ppu.dispstat.raw = halfword,
0x0400_0008 => bus.ppu.bg0.cnt.raw = halfword, 0x0400_0008...0x0400_000F => bus.ppu.bg[addr & 0x7].cnt.raw = halfword,
0x0400_0010 => bus.ppu.bg0.hofs.raw = halfword, 0x0400_0010 => bus.ppu.bg[0].hofs.raw = halfword, // TODO: Don't write out every HOFS / VOFS?
0x0400_0012 => bus.ppu.bg0.vofs.raw = halfword, 0x0400_0012 => bus.ppu.bg[0].vofs.raw = halfword,
0x0400_0014 => bus.ppu.bg[1].hofs.raw = halfword,
0x0400_0016 => bus.ppu.bg[1].vofs.raw = halfword,
0x0400_0018 => bus.ppu.bg[2].hofs.raw = halfword,
0x0400_001A => bus.ppu.bg[2].vofs.raw = halfword,
0x0400_001C => bus.ppu.bg[3].hofs.raw = halfword,
0x0400_001E => bus.ppu.bg[3].vofs.raw = halfword,
0x0400_0200 => bus.io.ie.raw = halfword, 0x0400_0200 => bus.io.ie.raw = halfword,
0x0400_0202 => bus.io.irq.raw = halfword, 0x0400_0202 => bus.io.irq.raw = halfword,
0x0400_0208 => bus.io.ime = halfword & 1 == 1, 0x0400_0208 => bus.io.ime = halfword & 1 == 1,

View File

@ -17,10 +17,8 @@ pub const Ppu = struct {
const Self = @This(); const Self = @This();
// Registers // Registers
bg0: Background,
bg1: Background, bg: [4]Background,
bg2: Background,
bg3: Background,
dispcnt: io.DisplayControl, dispcnt: io.DisplayControl,
dispstat: io.DisplayStatus, dispstat: io.DisplayStatus,
@ -49,10 +47,7 @@ pub const Ppu = struct {
.alloc = alloc, .alloc = alloc,
// Registers // Registers
.bg0 = Background.init(), .bg = [_]Background{Background.init()} ** 4,
.bg1 = Background.init(),
.bg2 = Background.init(),
.bg3 = Background.init(),
.dispcnt = .{ .raw = 0x0000 }, .dispcnt = .{ .raw = 0x0000 },
.dispstat = .{ .raw = 0x0000 }, .dispstat = .{ .raw = 0x0000 },
.vcount = .{ .raw = 0x0000 }, .vcount = .{ .raw = 0x0000 },
@ -65,15 +60,7 @@ pub const Ppu = struct {
self.palette.deinit(); self.palette.deinit();
} }
pub fn drawScanline(self: *Self) void { fn drawBackround(self: *Self, comptime n: u3, scanline: u32) void {
const bg_mode = self.dispcnt.bg_mode.read();
const scanline = self.vcount.scanline.read();
switch (bg_mode) {
0x0 => {
// TODO: Consider more than BG0
// TODO: Consider Scrolling
// The Current Scanline which will be copied into // The Current Scanline which will be copied into
// the Framebuffer // the Framebuffer
const start = framebuf_pitch * @as(usize, scanline); const start = framebuf_pitch * @as(usize, scanline);
@ -83,10 +70,10 @@ pub const Ppu = struct {
const charblock_len: u32 = 0x4000; const charblock_len: u32 = 0x4000;
const screenblock_len: u32 = 0x800; const screenblock_len: u32 = 0x800;
const cbb: u2 = self.bg0.cnt.char_base.read(); // Char Block Base const cbb: u2 = self.bg[n].cnt.char_base.read(); // Char Block Base
const sbb: u5 = self.bg0.cnt.screen_base.read(); // Screen Block Base const sbb: u5 = self.bg[n].cnt.screen_base.read(); // Screen Block Base
const is_8bpp: bool = self.bg0.cnt.colour_mode.read(); // Colour Mode const is_8bpp: bool = self.bg[n].cnt.colour_mode.read(); // Colour Mode
const size: u2 = self.bg0.cnt.size.read(); // Background Size const size: u2 = self.bg[n].cnt.size.read(); // Background Size
// In 4bpp: 1 byte represents two pixels so the length is (8 x 8) / 2 // In 4bpp: 1 byte represents two pixels so the length is (8 x 8) / 2
// In 8bpp: 1 byte represents one pixel so the length is 8 x 8 // In 8bpp: 1 byte represents one pixel so the length is 8 x 8
@ -97,13 +84,18 @@ pub const Ppu = struct {
const char_base: u32 = charblock_len * @as(u32, cbb); const char_base: u32 = charblock_len * @as(u32, cbb);
const screen_base: u32 = screenblock_len * @as(u32, sbb); const screen_base: u32 = screenblock_len * @as(u32, sbb);
const y = @as(u32, scanline); const vofs = self.bg[n].vofs.offset.read();
const hofs = self.bg[n].hofs.offset.read();
const y = scanline + vofs;
var i: u32 = 0;
while (i < width) : (i += 1) {
const x = i + hofs;
var x: u32 = 0;
while (x < width) : (x += 1) {
// Grab the Screen Entry from VRAM // Grab the Screen Entry from VRAM
const entry_addr = screen_base + tilemapOffset(size, x, y); const entry_addr = screen_base + tilemapOffset(size, x, y);
const entry = @bitCast(ScreenEntry, @as(u16, self.vram.buf[entry_addr + 1]) << 8 | @as(u16, self.vram.buf[entry_addr])); const entry = @bitCast(ScreenEntry, @as(u16, self.vram.get16(entry_addr)));
// Calculate the Address of the Tile in the designated Charblock // Calculate the Address of the Tile in the designated Charblock
// We also take this opportunity to flip tiles if necessary // We also take this opportunity to flip tiles if necessary
@ -126,10 +118,26 @@ pub const Ppu = struct {
break :blk pal_bank | tile; break :blk pal_bank | tile;
} else tile; } else tile;
std.mem.copy(u8, scanline_buf[x * 2 ..][0..2], self.palette.buf[colour * 2 ..][0..2]); std.mem.copy(u8, scanline_buf[i * 2 ..][0..2], self.palette.buf[colour * 2 ..][0..2]);
} }
std.mem.copy(u8, self.framebuf[start..][0..framebuf_pitch], &scanline_buf); std.mem.copy(u8, self.framebuf[start..][0..framebuf_pitch], &scanline_buf);
}
pub fn drawScanline(self: *Self) void {
const bg_mode = self.dispcnt.bg_mode.read();
const bg_enable = self.dispcnt.bg_enable.read();
const scanline = self.vcount.scanline.read();
switch (bg_mode) {
0x0 => {
var i: usize = 0;
while (i < 4) : (i += 1) {
if (i == self.bg[0].cnt.priority.read() and bg_enable & 1 == 1) self.drawBackround(0, scanline);
if (i == self.bg[1].cnt.priority.read() and bg_enable >> 1 & 1 == 1) self.drawBackround(1, scanline);
if (i == self.bg[2].cnt.priority.read() and bg_enable >> 2 & 1 == 1) self.drawBackround(2, scanline);
if (i == self.bg[3].cnt.priority.read() and bg_enable >> 3 & 1 == 1) self.drawBackround(3, scanline);
}
}, },
0x3 => { 0x3 => {
const start = framebuf_pitch * @as(usize, scanline); const start = framebuf_pitch * @as(usize, scanline);