diff --git a/src/Bus.zig b/src/Bus.zig index 72add6d..a1eec70 100644 --- a/src/Bus.zig +++ b/src/Bus.zig @@ -125,6 +125,7 @@ pub fn write16(self: *Self, addr: u32, halfword: u16) void { 0x0500_0000...0x05FF_FFFF => self.ppu.palette.set16(addr & 0x3FF, halfword), 0x0600_0000...0x0601_7FFF => self.ppu.vram.set16(addr - 0x0600_0000, halfword), 0x0700_0000...0x07FF_FFFF => self.ppu.oam.set16(addr & 0x3FF, halfword), + 0x0800_00C4, 0x0800_00C6, 0x0800_00C8 => log.warn("Tried to write 0x{X:0>4} to GPIO", .{halfword}), else => undWrite("Tried to write 0x{X:0>4} to 0x{X:0>8}", .{ halfword, addr }), } diff --git a/src/apu.zig b/src/apu.zig index 840a248..854db35 100644 --- a/src/apu.zig +++ b/src/apu.zig @@ -43,6 +43,10 @@ pub const Apu = struct { self.ch_vol_cnt.raw = (self.ch_vol_cnt.raw & 0xFF00) | byte; } + pub fn setSoundCntLHigh(self: *Self, byte: u8) void { + self.ch_vol_cnt.raw = @as(u16, byte) << 8 | (self.ch_vol_cnt.raw & 0xFF); + } + pub fn setBiasHigh(self: *Self, byte: u8) void { self.bias.raw = (@as(u16, byte) << 8) | (self.bias.raw & 0xFF); } @@ -51,9 +55,13 @@ pub const Apu = struct { const ToneSweep = struct { const Self = @This(); + /// NR10 sweep: io.Sweep, + /// NR11 duty: io.Duty, + /// NR12 envelope: io.Envelope, + /// NR13, NR14 freq: io.Frequency, fn init() Self { @@ -65,6 +73,10 @@ const ToneSweep = struct { }; } + pub fn setFreqLow(self: *Self, byte: u8) void { + self.freq.raw = (self.freq.raw & 0xFF00) | byte; + } + pub fn setFreqHigh(self: *Self, byte: u8) void { self.freq.raw = (@as(u16, byte) << 8) | (self.freq.raw & 0xFF); } @@ -73,8 +85,11 @@ const ToneSweep = struct { const Tone = struct { const Self = @This(); + /// NR21 duty: io.Duty, + /// NR22 envelope: io.Envelope, + /// NR23, NR24 freq: io.Frequency, fn init() Self { @@ -85,8 +100,12 @@ const Tone = struct { }; } + pub fn setFreqLow(self: *Self, byte: u8) void { + self.freq.raw = (self.freq.raw & 0xFF00) | byte; + } + pub fn setFreqHigh(self: *Self, byte: u8) void { - self.freq.raw = (self.freq.raw & 0x00FF) | (@as(u16, byte) << 8); + self.freq.raw = @as(u16, byte) << 8 | (self.freq.raw & 0xFF); } }; @@ -94,10 +113,13 @@ const Wave = struct { const Self = @This(); /// Write-only + /// NR30 select: io.WaveSelect, /// NR31 length: u8, + /// NR32 vol: io.WaveVolume, + /// NR33, NR34 freq: io.Frequency, fn init() Self { @@ -108,6 +130,14 @@ const Wave = struct { .length = 0, }; } + + pub fn setFreqLow(self: *Self, byte: u8) void { + self.freq.raw = (self.freq.raw & 0xFF00) | byte; + } + + pub fn setFreqHigh(self: *Self, byte: u8) void { + self.freq.raw = @as(u16, byte) << 8 | (self.freq.raw & 0xFF); + } }; const Noise = struct { @@ -116,8 +146,11 @@ const Noise = struct { /// Write-only /// NR41 len: u6, + /// NR42 envelope: io.Envelope, + /// NR43 poly: io.PolyCounter, + /// NR44 cnt: io.NoiseControl, fn init() Self { diff --git a/src/bus/io.zig b/src/bus/io.zig index b3ff351..b365004 100644 --- a/src/bus/io.zig +++ b/src/bus/io.zig @@ -124,6 +124,9 @@ pub fn read16(bus: *const Bus, addr: u32) u16 { // Sound 0x0400_0088 => bus.apu.bias.raw, + // DMA Transfers + 0x0400_00BA => bus.dma._0.cnt.raw, + // Timers 0x0400_0100 => bus.tim._0.counter(), 0x0400_0102 => bus.tim._0.cnt.raw, @@ -221,6 +224,8 @@ pub fn write16(bus: *Bus, addr: u32, halfword: u16) void { // Serial Communication 2 0x0400_0134 => log.warn("Wrote 0x{X:0>4} to RCNT", .{halfword}), + 0x0400_0140 => log.warn("Wrote 0x{X:0>4} to JOYCNT", .{halfword}), + 0x0400_0158 => log.warn("Wrote 0x{X:0>4} to JOYSTAT", .{halfword}), // Interrupts 0x0400_0200 => bus.io.ie.raw = halfword, @@ -239,6 +244,13 @@ pub fn read8(bus: *const Bus, addr: u32) u8 { 0x0400_0006 => @truncate(u8, bus.ppu.vcount.raw), // Sound + 0x0400_0060 => bus.apu.ch1.sweep.raw, + 0x0400_0063 => bus.apu.ch1.envelope.raw, + 0x0400_0069 => bus.apu.ch2.envelope.raw, + 0x0400_0073 => bus.apu.ch3.vol.raw, + 0x0400_0079 => bus.apu.ch4.envelope.raw, + 0x0400_007C => bus.apu.ch4.poly.raw, + 0x0400_0081 => @truncate(u8, bus.apu.ch_vol_cnt.raw >> 8), 0x0400_0089 => @truncate(u8, bus.apu.bias.raw >> 8), // Serial Communication 1 @@ -258,14 +270,26 @@ pub fn write8(bus: *Bus, addr: u32, byte: u8) void { 0x0400_0005 => bus.ppu.dispstat.raw = (@as(u16, byte) << 8) | (bus.ppu.dispstat.raw & 0xFF), // Sound + 0x0400_0060 => bus.apu.ch1.sweep.raw = byte, + 0x0400_0062 => bus.apu.ch1.duty.raw = byte, 0x0400_0063 => bus.apu.ch1.envelope.raw = byte, + 0x0400_0064 => bus.apu.ch1.setFreqLow(byte), 0x0400_0065 => bus.apu.ch1.setFreqHigh(byte), + 0x0400_0068 => bus.apu.ch2.duty.raw = byte, 0x0400_0069 => bus.apu.ch2.envelope.raw = byte, + 0x0400_006C => bus.apu.ch2.setFreqLow(byte), 0x0400_006D => bus.apu.ch2.setFreqHigh(byte), 0x0400_0070 => bus.apu.ch3.select.raw = byte, + 0x0400_0072 => bus.apu.ch3.length = byte, + 0x0400_0073 => bus.apu.ch3.vol.raw = byte, + 0x0400_0074 => bus.apu.ch3.setFreqLow(byte), + 0x0400_0075 => bus.apu.ch3.setFreqHigh(byte), + 0x0400_0078 => bus.apu.ch4.len = @truncate(u6, byte), 0x0400_0079 => bus.apu.ch4.envelope.raw = byte, + 0x0400_007C => bus.apu.ch4.poly.raw = byte, 0x0400_007D => bus.apu.ch4.cnt.raw = byte, 0x0400_0080 => bus.apu.setSoundCntLLow(byte), + 0x0400_0081 => bus.apu.setSoundCntLHigh(byte), 0x0400_0084 => bus.apu.setSoundCntX(byte >> 7 & 1 == 1), 0x0400_0089 => bus.apu.setBiasHigh(byte),