diff --git a/src/core/apu.zig b/src/core/apu.zig index 4ab9ffd..af56ef8 100644 --- a/src/core/apu.zig +++ b/src/core/apu.zig @@ -15,6 +15,9 @@ const Noise = @import("apu/Noise.zig"); const SoundFifo = std.fifo.LinearFifo(u8, .{ .Static = 0x20 }); const intToBytes = @import("../util.zig").intToBytes; +const setHi = @import("../util.zig").setHi; +const setLo = @import("../util.zig").setLo; + const log = std.log.scoped(.APU); pub const host_sample_rate = 1 << 15; @@ -24,28 +27,28 @@ pub fn read(comptime T: type, apu: *const Apu, addr: u32) ?T { return switch (T) { u16 => switch (byte) { - 0x60 => apu.ch1.getSoundCntL(), - 0x62 => apu.ch1.getSoundCntH(), - 0x64 => apu.ch1.getSoundCntX(), - 0x68 => apu.ch2.getSoundCntL(), - 0x6C => apu.ch2.getSoundCntH(), + 0x60 => apu.ch1.sound1CntL(), + 0x62 => apu.ch1.sound1CntH(), + 0x64 => apu.ch1.sound1CntX(), + 0x68 => apu.ch2.sound2CntL(), + 0x6C => apu.ch2.sound2CntH(), 0x70 => apu.ch3.select.raw & 0xE0, // SOUND3CNT_L - 0x72 => apu.ch3.getSoundCntH(), + 0x72 => apu.ch3.sound3CntH(), 0x74 => apu.ch3.freq.raw & 0x4000, // SOUND3CNT_X - 0x78 => apu.ch4.getSoundCntL(), - 0x7C => apu.ch4.getSoundCntH(), + 0x78 => apu.ch4.sound4CntL(), + 0x7C => apu.ch4.sound4CntH(), 0x80 => apu.psg_cnt.raw & 0xFF77, // SOUNDCNT_L 0x82 => apu.dma_cnt.raw & 0x770F, // SOUNDCNT_H - 0x84 => apu.getSoundCntX(), + 0x84 => apu.soundCntX(), 0x88 => apu.bias.raw, // SOUNDBIAS 0x90...0x9F => apu.ch3.wave_dev.read(T, apu.ch3.select, addr), else => util.io.read.undef(T, log, "Tried to perform a {} read to 0x{X:0>8}", .{ T, addr }), }, u8 => switch (byte) { - 0x60 => apu.ch1.getSoundCntL(), // NR10 + 0x60 => apu.ch1.sound1CntL(), // NR10 0x62 => apu.ch1.duty.raw, // NR11 0x63 => apu.ch1.envelope.raw, // NR12 0x68 => apu.ch2.duty.raw, // NR21 @@ -54,7 +57,7 @@ pub fn read(comptime T: type, apu: *const Apu, addr: u32) ?T { 0x79 => apu.ch4.envelope.raw, // NR42 0x7C => apu.ch4.poly.raw, // NR43 0x81 => @truncate(u8, apu.psg_cnt.raw >> 8), // NR51 - 0x84 => apu.getSoundCntX(), + 0x84 => apu.soundCntX(), 0x89 => @truncate(u8, apu.bias.raw >> 8), // SOUNDBIAS_H else => util.io.read.undef(T, log, "Tried to perform a {} read to 0x{X:0>8}", .{ T, addr }), }, @@ -68,14 +71,14 @@ pub fn write(comptime T: type, apu: *Apu, addr: u32, value: T) void { switch (T) { u32 => switch (byte) { - 0x60 => apu.ch1.setSoundCnt(value), - 0x64 => apu.ch1.setSoundCntX(&apu.fs, @truncate(u16, value)), - 0x68 => apu.ch2.setSoundCntL(@truncate(u16, value)), - 0x6C => apu.ch2.setSoundCntH(&apu.fs, @truncate(u16, value)), - 0x70 => apu.ch3.setSoundCnt(value), - 0x74 => apu.ch3.setSoundCntX(&apu.fs, @truncate(u16, value)), - 0x78 => apu.ch4.setSoundCntL(@truncate(u16, value)), - 0x7C => apu.ch4.setSoundCntH(&apu.fs, @truncate(u16, value)), + 0x60 => apu.ch1.setSound1Cnt(value), + 0x64 => apu.ch1.setSound1CntX(&apu.fs, @truncate(u16, value)), + 0x68 => apu.ch2.setSound2CntL(@truncate(u16, value)), + 0x6C => apu.ch2.setSound2CntH(&apu.fs, @truncate(u16, value)), + 0x70 => apu.ch3.setSound3Cnt(value), + 0x74 => apu.ch3.setSound3CntX(&apu.fs, @truncate(u16, value)), + 0x78 => apu.ch4.setSound4CntL(@truncate(u16, value)), + 0x7C => apu.ch4.setSound4CntH(&apu.fs, @truncate(u16, value)), 0x80 => apu.setSoundCnt(value), // WAVE_RAM @@ -85,19 +88,19 @@ pub fn write(comptime T: type, apu: *Apu, addr: u32, value: T) void { else => util.io.write.undef(log, "Tried to write 0x{X:0>8}{} to 0x{X:0>8}", .{ value, T, addr }), }, u16 => switch (byte) { - 0x60 => apu.ch1.setSoundCntL(@truncate(u8, value)), // SOUND1CNT_L - 0x62 => apu.ch1.setSoundCntH(value), - 0x64 => apu.ch1.setSoundCntX(&apu.fs, value), + 0x60 => apu.ch1.setSound1CntL(@truncate(u8, value)), // SOUND1CNT_L + 0x62 => apu.ch1.setSound1CntH(value), + 0x64 => apu.ch1.setSound1CntX(&apu.fs, value), - 0x68 => apu.ch2.setSoundCntL(value), - 0x6C => apu.ch2.setSoundCntH(&apu.fs, value), + 0x68 => apu.ch2.setSound2CntL(value), + 0x6C => apu.ch2.setSound2CntH(&apu.fs, value), - 0x70 => apu.ch3.setSoundCntL(@truncate(u8, value)), - 0x72 => apu.ch3.setSoundCntH(value), - 0x74 => apu.ch3.setSoundCntX(&apu.fs, value), + 0x70 => apu.ch3.setSound3CntL(@truncate(u8, value)), + 0x72 => apu.ch3.setSound3CntH(value), + 0x74 => apu.ch3.setSound3CntX(&apu.fs, value), - 0x78 => apu.ch4.setSoundCntL(value), - 0x7C => apu.ch4.setSoundCntH(&apu.fs, value), + 0x78 => apu.ch4.setSound4CntL(value), + 0x7C => apu.ch4.setSound4CntH(&apu.fs, value), 0x80 => apu.psg_cnt.raw = value, // SOUNDCNT_L 0x82 => apu.setSoundCntH(value), @@ -108,7 +111,7 @@ pub fn write(comptime T: type, apu: *Apu, addr: u32, value: T) void { else => util.io.write.undef(log, "Tried to write 0x{X:0>4}{} to 0x{X:0>8}", .{ value, T, addr }), }, u8 => switch (byte) { - 0x60 => apu.ch1.setSoundCntL(value), + 0x60 => apu.ch1.setSound1CntL(value), 0x62 => apu.ch1.setNr11(value), 0x63 => apu.ch1.setNr12(value), 0x64 => apu.ch1.setNr13(value), @@ -119,7 +122,7 @@ pub fn write(comptime T: type, apu: *Apu, addr: u32, value: T) void { 0x6C => apu.ch2.setNr23(value), 0x6D => apu.ch2.setNr24(&apu.fs, value), - 0x70 => apu.ch3.setSoundCntL(value), // NR30 + 0x70 => apu.ch3.setSound3CntL(value), // NR30 0x72 => apu.ch3.setNr31(value), 0x73 => apu.ch3.vol.raw = value, // NR32 0x74 => apu.ch3.setNr33(value), @@ -132,8 +135,8 @@ pub fn write(comptime T: type, apu: *Apu, addr: u32, value: T) void { 0x80 => apu.setNr50(value), 0x81 => apu.setNr51(value), - 0x82 => apu.setSoundCntHL(value), - 0x83 => apu.setSoundCntHH(value), + 0x82 => apu.setSoundCntH(setLo(u16, apu.dma_cnt.raw, value)), + 0x83 => apu.setSoundCntH(setHi(u16, apu.dma_cnt.raw, value)), 0x84 => apu.setSoundCntX(value >> 7 & 1 == 1), // NR52 0x89 => apu.setSoundBiasH(value), 0x90...0x9F => apu.ch3.wave_dev.write(T, apu.ch3.select, addr, value), @@ -194,12 +197,12 @@ pub const Apu = struct { .is_buffer_full = false, }; - sched.push(.SampleAudio, apu.sampleTicks()); + sched.push(.SampleAudio, apu.interval()); sched.push(.{ .ApuChannel = 0 }, @import("apu/signal/Square.zig").interval); sched.push(.{ .ApuChannel = 1 }, @import("apu/signal/Square.zig").interval); sched.push(.{ .ApuChannel = 2 }, @import("apu/signal/Wave.zig").interval); sched.push(.{ .ApuChannel = 3 }, @import("apu/signal/Lfsr.zig").interval); - sched.push(.FrameSequencer, ((1 << 24) / 512)); + sched.push(.FrameSequencer, FrameSequencer.interval); return apu; } @@ -217,18 +220,6 @@ pub const Apu = struct { self.setSoundCntH(@truncate(u16, value >> 16)); } - /// SOUNDCNT_H_L - fn setSoundCntHL(self: *Self, value: u8) void { - const merged = (self.dma_cnt.raw & 0xFF00) | value; - self.setSoundCntH(merged); - } - - /// SOUNDCNT_H_H - fn setSoundCntHH(self: *Self, value: u8) void { - const merged = (self.dma_cnt.raw & 0x00FF) | (@as(u16, value) << 8); - self.setSoundCntH(merged); - } - /// SOUNDCNT_H pub fn setSoundCntH(self: *Self, value: u16) void { const new: io.DmaSoundControl = .{ .raw = value }; @@ -260,7 +251,7 @@ pub const Apu = struct { } /// NR52 - pub fn getSoundCntX(self: *const Self) u8 { + pub fn soundCntX(self: *const Self) u8 { const apu_enable: u8 = @boolToInt(self.cnt.apu_enable.read()); const ch1_enable: u8 = @boolToInt(self.ch1.enabled); @@ -286,7 +277,7 @@ pub const Apu = struct { } pub fn sampleAudio(self: *Self, late: u64) void { - self.sched.push(.SampleAudio, self.sampleTicks() -| late); + self.sched.push(.SampleAudio, self.interval() -| late); // Whether the APU is busy or not is determined by the main loop in emu.zig // This should only ever be true (because this side of the emu is single threaded) @@ -355,6 +346,7 @@ pub const Apu = struct { } fn replaceSDLResampler(self: *Self) void { + @setCold(true); const sample_rate = Self.sampleRate(self.bias.sampling_cycle.read()); log.info("Sample Rate changed from {}Hz to {}Hz", .{ Self.sampleRate(self.sampling_cycle), sample_rate }); @@ -367,7 +359,7 @@ pub const Apu = struct { self.stream = SDL.SDL_NewAudioStream(SDL.AUDIO_U16, 2, @intCast(c_int, sample_rate), SDL.AUDIO_U16, 2, host_sample_rate).?; } - fn sampleTicks(self: *const Self) u64 { + fn interval(self: *const Self) u64 { return (1 << 24) / Self.sampleRate(self.bias.sampling_cycle.read()); } @@ -393,19 +385,19 @@ pub const Apu = struct { } fn tick(self: *Self, comptime kind: Tick) void { + self.ch1.tick(kind); + switch (kind) { .Length => { - self.ch1.tick(kind); self.ch2.tick(kind); self.ch3.tick(kind); self.ch4.tick(kind); }, .Envelope => { - self.ch1.tick(kind); self.ch2.tick(kind); self.ch4.tick(kind); }, - .Sweep => self.ch1.tick(kind), + .Sweep => {}, // Already handled above (only for Ch1) } } @@ -464,6 +456,7 @@ const DmaSoundKind = enum { }; pub const FrameSequencer = struct { + const interval = (1 << 24) / 512; const Self = @This(); step: u3, diff --git a/src/core/apu/Noise.zig b/src/core/apu/Noise.zig index a5fca21..f9c7321 100644 --- a/src/core/apu/Noise.zig +++ b/src/core/apu/Noise.zig @@ -67,12 +67,12 @@ pub fn tick(self: *Self, comptime kind: Tick) void { } /// NR41, NR42 -pub fn getSoundCntL(self: *const Self) u16 { +pub fn sound4CntL(self: *const Self) u16 { return @as(u16, self.envelope.raw) << 8; } /// NR41, NR42 -pub fn setSoundCntL(self: *Self, value: u16) void { +pub fn setSound4CntL(self: *Self, value: u16) void { self.setNr41(@truncate(u8, value)); self.setNr42(@truncate(u8, value >> 8)); } @@ -90,12 +90,12 @@ pub fn setNr42(self: *Self, value: u8) void { } /// NR43, NR44 -pub fn getSoundCntH(self: *const Self) u16 { +pub fn sound4CntH(self: *const Self) u16 { return @as(u16, self.poly.raw & 0x40) << 8 | self.cnt.raw; } /// NR43, NR44 -pub fn setSoundCntH(self: *Self, fs: *const FrameSequencer, value: u16) void { +pub fn setSound4CntH(self: *Self, fs: *const FrameSequencer, value: u16) void { self.poly.raw = @truncate(u8, value); self.setNr44(fs, @truncate(u8, value >> 8)); } diff --git a/src/core/apu/Tone.zig b/src/core/apu/Tone.zig index b69b732..cb5daee 100644 --- a/src/core/apu/Tone.zig +++ b/src/core/apu/Tone.zig @@ -68,12 +68,12 @@ pub fn onToneEvent(self: *Self, late: u64) void { } /// NR21, NR22 -pub fn getSoundCntL(self: *const Self) u16 { +pub fn sound2CntL(self: *const Self) u16 { return @as(u16, self.envelope.raw) << 8 | (self.duty.raw & 0xC0); } /// NR21, NR22 -pub fn setSoundCntL(self: *Self, value: u16) void { +pub fn setSound2CntL(self: *Self, value: u16) void { self.setNr21(@truncate(u8, value)); self.setNr22(@truncate(u8, value >> 8)); } @@ -91,12 +91,12 @@ pub fn setNr22(self: *Self, value: u8) void { } /// NR23, NR24 -pub fn getSoundCntH(self: *const Self) u16 { +pub fn sound2CntH(self: *const Self) u16 { return self.freq.raw & 0x4000; } /// NR23, NR24 -pub fn setSoundCntH(self: *Self, fs: *const FrameSequencer, value: u16) void { +pub fn setSound2CntH(self: *Self, fs: *const FrameSequencer, value: u16) void { self.setNr23(@truncate(u8, value)); self.setNr24(fs, @truncate(u8, value >> 8)); } diff --git a/src/core/apu/ToneSweep.zig b/src/core/apu/ToneSweep.zig index 1c152b9..954bf7e 100644 --- a/src/core/apu/ToneSweep.zig +++ b/src/core/apu/ToneSweep.zig @@ -78,18 +78,18 @@ pub fn onToneSweepEvent(self: *Self, late: u64) void { } /// NR10, NR11, NR12 -pub fn setSoundCnt(self: *Self, value: u32) void { - self.setSoundCntL(@truncate(u8, value)); - self.setSoundCntH(@truncate(u16, value >> 16)); +pub fn setSound1Cnt(self: *Self, value: u32) void { + self.setSound1CntL(@truncate(u8, value)); + self.setSound1CntH(@truncate(u16, value >> 16)); } /// NR10 -pub fn getSoundCntL(self: *const Self) u8 { +pub fn sound1CntL(self: *const Self) u8 { return self.sweep.raw & 0x7F; } /// NR10 -pub fn setSoundCntL(self: *Self, value: u8) void { +pub fn setSound1CntL(self: *Self, value: u8) void { const new = io.Sweep{ .raw = value }; if (self.sweep.direction.read() and !new.direction.read()) { @@ -104,12 +104,12 @@ pub fn setSoundCntL(self: *Self, value: u8) void { } /// NR11, NR12 -pub fn getSoundCntH(self: *const Self) u16 { +pub fn sound1CntH(self: *const Self) u16 { return @as(u16, self.envelope.raw) << 8 | (self.duty.raw & 0xC0); } /// NR11, NR12 -pub fn setSoundCntH(self: *Self, value: u16) void { +pub fn setSound1CntH(self: *Self, value: u16) void { self.setNr11(@truncate(u8, value)); self.setNr12(@truncate(u8, value >> 8)); } @@ -127,12 +127,12 @@ pub fn setNr12(self: *Self, value: u8) void { } /// NR13, NR14 -pub fn getSoundCntX(self: *const Self) u16 { +pub fn sound1CntX(self: *const Self) u16 { return self.freq.raw & 0x4000; } /// NR13, NR14 -pub fn setSoundCntX(self: *Self, fs: *const FrameSequencer, value: u16) void { +pub fn setSound1CntX(self: *Self, fs: *const FrameSequencer, value: u16) void { self.setNr13(@truncate(u8, value)); self.setNr14(fs, @truncate(u8, value >> 8)); } diff --git a/src/core/apu/Wave.zig b/src/core/apu/Wave.zig index b66f932..3eaa6dc 100644 --- a/src/core/apu/Wave.zig +++ b/src/core/apu/Wave.zig @@ -60,24 +60,24 @@ pub fn tick(self: *Self, comptime kind: Tick) void { } /// NR30, NR31, NR32 -pub fn setSoundCnt(self: *Self, value: u32) void { - self.setSoundCntL(@truncate(u8, value)); - self.setSoundCntH(@truncate(u16, value >> 16)); +pub fn setSound3Cnt(self: *Self, value: u32) void { + self.setSound3CntL(@truncate(u8, value)); + self.setSound3CntH(@truncate(u16, value >> 16)); } /// NR30 -pub fn setSoundCntL(self: *Self, value: u8) void { +pub fn setSound3CntL(self: *Self, value: u8) void { self.select.raw = value; if (!self.select.enabled.read()) self.enabled = false; } /// NR31, NR32 -pub fn getSoundCntH(self: *const Self) u16 { +pub fn sound3CntH(self: *const Self) u16 { return @as(u16, self.length & 0xE0) << 8; } /// NR31, NR32 -pub fn setSoundCntH(self: *Self, value: u16) void { +pub fn setSound3CntH(self: *Self, value: u16) void { self.setNr31(@truncate(u8, value)); self.vol.raw = (@truncate(u8, value >> 8)); } @@ -89,7 +89,7 @@ pub fn setNr31(self: *Self, len: u8) void { } /// NR33, NR34 -pub fn setSoundCntX(self: *Self, fs: *const FrameSequencer, value: u16) void { +pub fn setSound3CntX(self: *Self, fs: *const FrameSequencer, value: u16) void { self.setNr33(@truncate(u8, value)); self.setNr34(fs, @truncate(u8, value >> 8)); } diff --git a/src/core/bus/dma.zig b/src/core/bus/dma.zig index 4678642..0d25bd0 100644 --- a/src/core/bus/dma.zig +++ b/src/core/bus/dma.zig @@ -8,6 +8,9 @@ const Arm7tdmi = @import("../cpu.zig").Arm7tdmi; pub const DmaTuple = std.meta.Tuple(&[_]type{ DmaController(0), DmaController(1), DmaController(2), DmaController(3) }); const log = std.log.scoped(.DmaTransfer); +const setHi = util.setHi; +const setLo = util.setLo; + pub fn create() DmaTuple { return .{ DmaController(0).init(), DmaController(1).init(), DmaController(2).init(), DmaController(3).init() }; } @@ -55,31 +58,31 @@ pub fn write(comptime T: type, dma: *DmaTuple, addr: u32, value: T) void { else => util.io.write.undef(log, "Tried to write 0x{X:0>8}{} to 0x{X:0>8}", .{ value, T, addr }), }, u16 => switch (byte) { - 0xB0 => dma.*[0].setDmasad(setU32L(dma.*[0].sad, value)), - 0xB2 => dma.*[0].setDmasad(setU32H(dma.*[0].sad, value)), - 0xB4 => dma.*[0].setDmadad(setU32L(dma.*[0].dad, value)), - 0xB6 => dma.*[0].setDmadad(setU32H(dma.*[0].dad, value)), + 0xB0 => dma.*[0].setDmasad(setLo(u32, dma.*[0].sad, value)), + 0xB2 => dma.*[0].setDmasad(setHi(u32, dma.*[0].sad, value)), + 0xB4 => dma.*[0].setDmadad(setLo(u32, dma.*[0].dad, value)), + 0xB6 => dma.*[0].setDmadad(setHi(u32, dma.*[0].dad, value)), 0xB8 => dma.*[0].setDmacntL(value), 0xBA => dma.*[0].setDmacntH(value), - 0xBC => dma.*[1].setDmasad(setU32L(dma.*[1].sad, value)), - 0xBE => dma.*[1].setDmasad(setU32H(dma.*[1].sad, value)), - 0xC0 => dma.*[1].setDmadad(setU32L(dma.*[1].dad, value)), - 0xC2 => dma.*[1].setDmadad(setU32H(dma.*[1].dad, value)), + 0xBC => dma.*[1].setDmasad(setLo(u32, dma.*[1].sad, value)), + 0xBE => dma.*[1].setDmasad(setHi(u32, dma.*[1].sad, value)), + 0xC0 => dma.*[1].setDmadad(setLo(u32, dma.*[1].dad, value)), + 0xC2 => dma.*[1].setDmadad(setHi(u32, dma.*[1].dad, value)), 0xC4 => dma.*[1].setDmacntL(value), 0xC6 => dma.*[1].setDmacntH(value), - 0xC8 => dma.*[2].setDmasad(setU32L(dma.*[2].sad, value)), - 0xCA => dma.*[2].setDmasad(setU32H(dma.*[2].sad, value)), - 0xCC => dma.*[2].setDmadad(setU32L(dma.*[2].dad, value)), - 0xCE => dma.*[2].setDmadad(setU32H(dma.*[2].dad, value)), + 0xC8 => dma.*[2].setDmasad(setLo(u32, dma.*[2].sad, value)), + 0xCA => dma.*[2].setDmasad(setHi(u32, dma.*[2].sad, value)), + 0xCC => dma.*[2].setDmadad(setLo(u32, dma.*[2].dad, value)), + 0xCE => dma.*[2].setDmadad(setHi(u32, dma.*[2].dad, value)), 0xD0 => dma.*[2].setDmacntL(value), 0xD2 => dma.*[2].setDmacntH(value), - 0xD4 => dma.*[3].setDmasad(setU32L(dma.*[3].sad, value)), - 0xD6 => dma.*[3].setDmasad(setU32H(dma.*[3].sad, value)), - 0xD8 => dma.*[3].setDmadad(setU32L(dma.*[3].dad, value)), - 0xDA => dma.*[3].setDmadad(setU32H(dma.*[3].dad, value)), + 0xD4 => dma.*[3].setDmasad(setLo(u32, dma.*[3].sad, value)), + 0xD6 => dma.*[3].setDmasad(setHi(u32, dma.*[3].sad, value)), + 0xD8 => dma.*[3].setDmadad(setLo(u32, dma.*[3].dad, value)), + 0xDA => dma.*[3].setDmadad(setHi(u32, dma.*[3].dad, value)), 0xDC => dma.*[3].setDmacntL(value), 0xDE => dma.*[3].setDmacntH(value), else => util.io.write.undef(log, "Tried to write 0x{X:0>4}{} to 0x{X:0>8}", .{ value, T, addr }), @@ -283,11 +286,3 @@ const DmaKind = enum(u2) { VBlank, Special, }; - -fn setU32L(left: u32, right: u16) u32 { - return (left & 0xFFFF_0000) | right; -} - -fn setU32H(left: u32, right: u16) u32 { - return (left & 0x0000_FFFF) | (@as(u32, right) << 16); -} diff --git a/src/core/bus/io.zig b/src/core/bus/io.zig index e6f4850..d33e015 100644 --- a/src/core/bus/io.zig +++ b/src/core/bus/io.zig @@ -11,6 +11,9 @@ const Bus = @import("../Bus.zig"); const DmaController = @import("dma.zig").DmaController; const Scheduler = @import("../scheduler.zig").Scheduler; +const setHi = util.setLo; +const setLo = util.setHi; + const log = std.log.scoped(.@"I/O"); pub const Io = struct { @@ -233,18 +236,18 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 0x0400_0022 => bus.ppu.aff_bg[0].pb = @bitCast(i16, value), 0x0400_0024 => bus.ppu.aff_bg[0].pc = @bitCast(i16, value), 0x0400_0026 => bus.ppu.aff_bg[0].pd = @bitCast(i16, value), - 0x0400_0028 => bus.ppu.aff_bg[0].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[0].x) & 0xFFFF_0000 | value), - 0x0400_002A => bus.ppu.aff_bg[0].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[0].x) & 0x0000_FFFF | (@as(u32, value) << 16)), - 0x0400_002C => bus.ppu.aff_bg[0].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[0].y) & 0xFFFF_0000 | value), - 0x0400_002E => bus.ppu.aff_bg[0].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[0].y) & 0x0000_FFFF | (@as(u32, value) << 16)), + 0x0400_0028 => bus.ppu.aff_bg[0].x = @bitCast(i32, setLo(u32, @bitCast(u32, bus.ppu.aff_bg[0].x), value)), + 0x0400_002A => bus.ppu.aff_bg[0].x = @bitCast(i32, setHi(u32, @bitCast(u32, bus.ppu.aff_bg[0].x), value)), + 0x0400_002C => bus.ppu.aff_bg[0].y = @bitCast(i32, setLo(u32, @bitCast(u32, bus.ppu.aff_bg[0].y), value)), + 0x0400_002E => bus.ppu.aff_bg[0].y = @bitCast(i32, setHi(u32, @bitCast(u32, bus.ppu.aff_bg[0].y), value)), 0x0400_0030 => bus.ppu.aff_bg[1].pa = @bitCast(i16, value), 0x0400_0032 => bus.ppu.aff_bg[1].pb = @bitCast(i16, value), 0x0400_0034 => bus.ppu.aff_bg[1].pc = @bitCast(i16, value), 0x0400_0036 => bus.ppu.aff_bg[1].pd = @bitCast(i16, value), - 0x0400_0038 => bus.ppu.aff_bg[1].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[1].x) & 0xFFFF_0000 | value), - 0x0400_003A => bus.ppu.aff_bg[1].x = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[1].x) & 0x0000_FFFF | (@as(u32, value) << 16)), - 0x0400_003C => bus.ppu.aff_bg[1].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[1].y) & 0xFFFF_0000 | value), - 0x0400_003E => bus.ppu.aff_bg[1].y = @bitCast(i32, @bitCast(u32, bus.ppu.aff_bg[1].y) & 0x0000_FFFF | (@as(u32, value) << 16)), + 0x0400_0038 => bus.ppu.aff_bg[1].x = @bitCast(i32, setLo(u32, @bitCast(u32, bus.ppu.aff_bg[1].x), value)), + 0x0400_003A => bus.ppu.aff_bg[1].x = @bitCast(i32, setHi(u32, @bitCast(u32, bus.ppu.aff_bg[1].x), value)), + 0x0400_003C => bus.ppu.aff_bg[1].y = @bitCast(i32, setLo(u32, @bitCast(u32, bus.ppu.aff_bg[1].y), value)), + 0x0400_003E => bus.ppu.aff_bg[1].y = @bitCast(i32, setHi(u32, @bitCast(u32, bus.ppu.aff_bg[1].y), value)), 0x0400_0040 => bus.ppu.win.h[0].raw = value, 0x0400_0042 => bus.ppu.win.h[1].raw = value, 0x0400_0044 => bus.ppu.win.v[0].raw = value, @@ -296,16 +299,16 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { }, u8 => switch (address) { // Display - 0x0400_0004 => bus.ppu.dispstat.raw = (bus.ppu.dispstat.raw & 0xFF00) | value, - 0x0400_0005 => bus.ppu.dispstat.raw = (@as(u16, value) << 8) | (bus.ppu.dispstat.raw & 0xFF), - 0x0400_0008 => bus.ppu.bg[0].cnt.raw = (bus.ppu.bg[0].cnt.raw & 0xFF00) | value, - 0x0400_0009 => bus.ppu.bg[0].cnt.raw = (@as(u16, value) << 8) | (bus.ppu.bg[0].cnt.raw & 0xFF), - 0x0400_000A => bus.ppu.bg[1].cnt.raw = (bus.ppu.bg[1].cnt.raw & 0xFF00) | value, - 0x0400_000B => bus.ppu.bg[1].cnt.raw = (@as(u16, value) << 8) | (bus.ppu.bg[1].cnt.raw & 0xFF), - 0x0400_0048 => bus.ppu.win.setInL(value), - 0x0400_0049 => bus.ppu.win.setInH(value), - 0x0400_004A => bus.ppu.win.setOutL(value), - 0x0400_0054 => bus.ppu.bldy.raw = (bus.ppu.bldy.raw & 0xFF00) | value, + 0x0400_0004 => bus.ppu.dispstat.raw = setLo(u16, bus.ppu.dispstat.raw, value), + 0x0400_0005 => bus.ppu.dispstat.raw = setHi(u16, bus.ppu.dispstat.raw, value), + 0x0400_0008 => bus.ppu.bg[0].cnt.raw = setLo(u16, bus.ppu.bg[0].cnt.raw, value), + 0x0400_0009 => bus.ppu.bg[0].cnt.raw = setHi(u16, bus.ppu.bg[0].cnt.raw, value), + 0x0400_000A => bus.ppu.bg[1].cnt.raw = setLo(u16, bus.ppu.bg[1].cnt.raw, value), + 0x0400_000B => bus.ppu.bg[1].cnt.raw = setHi(u16, bus.ppu.bg[1].cnt.raw, value), + 0x0400_0048 => bus.ppu.win.in.raw = setLo(u16, bus.ppu.win.in.raw, value), + 0x0400_0049 => bus.ppu.win.in.raw = setHi(u16, bus.ppu.win.in.raw, value), + 0x0400_004A => bus.ppu.win.out.raw = setLo(u16, bus.ppu.win.out.raw, value), + 0x0400_0054 => bus.ppu.bldy.raw = setLo(u16, bus.ppu.bldy.raw, value), // Sound 0x0400_0060...0x0400_00A7 => apu.write(T, &bus.apu, address, value), diff --git a/src/core/ppu.zig b/src/core/ppu.zig index d1b3f11..c7564e1 100644 --- a/src/core/ppu.zig +++ b/src/core/ppu.zig @@ -808,18 +808,6 @@ const Window = struct { self.in.raw = @truncate(u16, value); self.out.raw = @truncate(u16, value >> 16); } - - pub fn setInL(self: *Self, value: u8) void { - self.in.raw = (self.in.raw & 0xFF00) | value; - } - - pub fn setInH(self: *Self, value: u8) void { - self.in.raw = (self.in.raw & 0x00FF) | (@as(u16, value) << 8); - } - - pub fn setOutL(self: *Self, value: u8) void { - self.out.raw = (self.out.raw & 0xFF00) | value; - } }; const Background = struct { diff --git a/src/util.zig b/src/util.zig index 1a4f3c2..848828f 100644 --- a/src/util.zig +++ b/src/util.zig @@ -268,3 +268,32 @@ pub const audio = struct { }; }; }; + +/// Sets the high bits of an integer to a value +pub inline fn setHi(comptime T: type, left: T, right: HalfInt(T)) T { + return switch (T) { + u32 => (left & 0xFFFF_0000) | right, + u16 => (left & 0xFF00) | right, + u8 => (left & 0xF0) | right, + else => @compileError("unsupported type"), + }; +} + +/// sets the low bits of an integer to a value +pub inline fn setLo(comptime T: type, left: T, right: HalfInt(T)) T { + return switch (T) { + u32 => (left & 0x0000_FFFF) | @as(u32, right) << 16, + u16 => (left & 0x00FF) | @as(u16, right) << 8, + u8 => (left & 0x0F) | @as(u8, right) << 4, + else => @compileError("unsupported type"), + }; +} + +/// The Integer type which corresponds to T with exactly half the amount of bits +fn HalfInt(comptime T: type) type { + const type_info = @typeInfo(T); + comptime std.debug.assert(type_info == .Int); // Type must be an integer + comptime std.debug.assert(type_info.Int.bits % 2 == 0); // Type must have an even amount of bits + + return std.meta.Int(type_info.Int.signedness, type_info.Int.bits >> 1); +}