diff --git a/src/apu.zig b/src/apu.zig index 3b0c025..5c5334e 100644 --- a/src/apu.zig +++ b/src/apu.zig @@ -966,24 +966,20 @@ const WaveDevice = struct { fn reloadTimer(self: *Self, value: u11) void { self.sched.removeScheduledEvent(.{ .ApuChannel = 2 }); - const timer = (2048 - @as(u64, value)) * 4; - self.timer = @truncate(u11, timer); - self.sched.push(.{ .ApuChannel = 2 }, timer * tickInterval); + self.timer = (@as(u16, 2048) - value) * 2; + self.sched.push(.{ .ApuChannel = 2 }, @as(u64, self.timer) * tickInterval); } fn handleTimerOverflow(self: *Self, cnt_freq: io.Frequency, cnt_sel: io.WaveSelect, late: u64) void { - const timer = (2048 - @as(u64, cnt_freq.frequency.read())) * 2; - - self.timer = @truncate(u12, timer); - if (cnt_sel.dimension.read()) { self.offset = (self.offset + 1) % 0x40; // 0x20 bytes (both banks), which contain 2 samples each } else { self.offset = (self.offset + 1) % 0x20; // 0x10 bytes, which contain 2 samples each } - self.sched.push(.{ .ApuChannel = 2 }, timer * tickInterval -| late); + self.timer = (@as(u16, 2048) - cnt_freq.frequency.read()) * 2; + self.sched.push(.{ .ApuChannel = 2 }, @as(u64, self.timer) * tickInterval -| late); } fn sample(self: *const Self, cnt: io.WaveSelect) u4 { @@ -1046,7 +1042,7 @@ const SquareWave = struct { pos: u3, sched: *Scheduler, - timer: u12, + timer: u16, pub fn init(sched: *Scheduler) Self { return .{ @@ -1089,22 +1085,19 @@ const SquareWave = struct { } fn handleTimerOverflow(self: *Self, comptime kind: ChannelKind, cnt: io.Frequency, late: u64) void { - const timer = (2048 - @as(u64, cnt.frequency.read())) * 4; - - self.timer = @truncate(u12, timer); self.pos +%= 1; - self.sched.push(.{ .ApuChannel = if (kind == .Ch1) 0 else 1 }, timer * tickInterval -| late); + self.timer = (@as(u16, 2048) - cnt.frequency.read()) * 4; + self.sched.push(.{ .ApuChannel = if (kind == .Ch1) 0 else 1 }, @as(u64, self.timer) * tickInterval -| late); } fn reloadTimer(self: *Self, comptime kind: ChannelKind, value: u11) void { self.sched.removeScheduledEvent(.{ .ApuChannel = if (kind == .Ch1) 0 else 1 }); - const tmp: u64 = (2048 - @as(u64, value)) * 4; // What Freq Timer should be assuming no weird behaviour - const timer = (tmp & ~@as(u64, 0x3)) | self.timer & 0x3; // Keep the last two bits from the old timer - self.timer = @truncate(u12, timer); + const tmp = (@as(u16, 2048) - value) * 4; // What Freq Timer should be assuming no weird behaviour + self.timer = (tmp & ~@as(u16, 0x3)) | self.timer & 0x3; // Keep the last two bits from the old timer; - self.sched.push(.{ .ApuChannel = if (kind == .Ch1) 0 else 1 }, timer * tickInterval); + self.sched.push(.{ .ApuChannel = if (kind == .Ch1) 0 else 1 }, @as(u64, self.timer) * tickInterval); } fn sample(self: *const Self, cnt: io.Duty) u1 { @@ -1163,14 +1156,17 @@ const Lfsr = struct { self.sched.removeScheduledEvent(.{ .ApuChannel = 3 }); const div = Self.divisor(poly.div_ratio.read()); - const timer = @as(u64, div << poly.shift.read()); - - self.sched.push(.{ .ApuChannel = 3 }, timer * tickInterval); + const timer = div << poly.shift.read(); + self.sched.push(.{ .ApuChannel = 3 }, @as(u64, timer) * tickInterval); } fn handleTimerOverflow(self: *Self, poly: io.PolyCounter, late: u64) void { + // Obscure: "Using a noise channel clock shift of 14 or 15 + // results in the LFSR receiving no clocks." + if (poly.shift.read() >= 14) return; + const div = Self.divisor(poly.div_ratio.read()); - const timer = @as(u64, div << poly.shift.read()); + const timer = div << poly.shift.read(); const tmp = (self.shift & 1) ^ ((self.shift & 2) >> 1); self.shift = (self.shift >> 1) | (tmp << 14); @@ -1178,7 +1174,7 @@ const Lfsr = struct { if (poly.width.read()) self.shift = (self.shift & ~@as(u15, 0x40)) | tmp << 6; - self.sched.push(.{ .ApuChannel = 3 }, timer * tickInterval -| late); + self.sched.push(.{ .ApuChannel = 3 }, @as(u64, timer) * tickInterval -| late); } fn divisor(code: u3) u16 {