Skip to main content

nes_sim/
apu.rs

1use crate::cartridge::TVSystem;
2use crate::savestate::{SaveStateError, StateReader, StateWriter};
3
4pub(crate) mod dmc;
5pub(crate) mod noise;
6pub(crate) mod pulse;
7pub(crate) mod triangle;
8
9use dmc::{DmcDmaRequest, DmcState};
10use noise::NoiseChannel;
11use pulse::PulseChannel;
12use triangle::TriangleChannel;
13
14const CPU_CLOCK_NTSC: u64 = 1_789_773;
15const DEFAULT_SAMPLE_RATE: u32 = 44_100;
16const FRAME_SEQUENCER_DIVIDER: u16 = 7_456;
17
18// 使用 Q31.31 定点数格式进行相位跟踪
19// 高 32 位是整数部分,低 32 位是小数部分
20const PHASE_SCALE: u64 = 1u64 << 32;
21
22pub const LENGTH_TABLE: [u8; 32] = [
23    10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22,
24    192, 24, 72, 26, 16, 28, 32, 30,
25];
26
27pub trait ExpansionAudioChip {
28    fn cpu_write(&mut self, _addr: u16, _data: u8) {}
29    #[allow(dead_code)]
30    fn cpu_read(&mut self, _addr: u16) -> Option<u8> {
31        None
32    }
33    fn tick_cpu_cycle(&mut self) {}
34    fn clock_quarter_frame(&mut self) {}
35    fn clock_half_frame(&mut self) {}
36    fn irq_line(&self) -> bool {
37        false
38    }
39    fn output_sample(&self) -> f32 {
40        0.0
41    }
42}
43
44pub struct APU {
45    pulse1: PulseChannel,
46    pulse2: PulseChannel,
47    triangle: TriangleChannel,
48    noise: NoiseChannel,
49    dmc: DmcState,
50    frame_irq_inhibit: bool,
51    frame_irq_flag: bool,
52    frame_mode_five_step: bool,
53    frame_step: u8,
54    frame_divider: u16,
55    pending_dmc_dma: Option<DmcDmaRequest>,
56    sample_rate: u32,
57    // 使用 Q31.31 定点数:每个 CPU 周期增加 PHASE_SCALE / cycles_per_sample
58    cycles_per_sample_fixed: u64,
59    sample_phase_fixed: u64,
60    // 整数累加器,避免每 CPU 周期的浮点运算
61    sample_accum_pulse: i64,
62    sample_accum_tri: i64,
63    sample_accum_noise: i64,
64    sample_accum_dmc: i64,
65    sample_accum_exp: i64,
66    sample_accum_count: u32,
67    audio_samples: Vec<f32>,
68    expansions: Vec<Box<dyn ExpansionAudioChip>>,
69    apu_subclock_even: bool,
70    debug_mute_mask: u8,
71}
72
73impl APU {
74    pub fn new() -> Self {
75        let sample_rate = DEFAULT_SAMPLE_RATE;
76        // 使用定点数:cycles_per_sample_fixed = (PHASE_SCALE * sample_rate) / cpu_clock
77        // 这样 sample_phase_fixed 每次增加 cycles_per_sample_fixed
78        let cycles_per_sample_fixed = (PHASE_SCALE * sample_rate as u64) / CPU_CLOCK_NTSC;
79        Self {
80            pulse1: PulseChannel::new(true),
81            pulse2: PulseChannel::new(false),
82            triangle: TriangleChannel::default(),
83            noise: NoiseChannel::default(),
84            dmc: DmcState::default(),
85            frame_irq_inhibit: false,
86            frame_irq_flag: false,
87            frame_mode_five_step: false,
88            frame_step: 0,
89            frame_divider: FRAME_SEQUENCER_DIVIDER,
90            pending_dmc_dma: None,
91            sample_rate,
92            cycles_per_sample_fixed,
93            sample_phase_fixed: 0,
94            sample_accum_pulse: 0,
95            sample_accum_tri: 0,
96            sample_accum_noise: 0,
97            sample_accum_dmc: 0,
98            sample_accum_exp: 0,
99            sample_accum_count: 0,
100            audio_samples: Vec::new(),
101            expansions: Vec::new(),
102            apu_subclock_even: false,
103            debug_mute_mask: 0,
104        }
105    }
106
107    pub fn add_expansion_chip(&mut self, chip: Box<dyn ExpansionAudioChip>) {
108        self.expansions.push(chip);
109    }
110
111    pub fn set_tv_system(&mut self, tv: TVSystem) {
112        self.dmc.set_tv_system(tv);
113    }
114
115    pub fn reset(&mut self) {
116        self.frame_irq_flag = false;
117        self.frame_step = 0;
118        self.frame_divider = FRAME_SEQUENCER_DIVIDER;
119        self.pending_dmc_dma = None;
120        self.sample_phase_fixed = 0;
121        self.sample_accum_pulse = 0;
122        self.sample_accum_tri = 0;
123        self.sample_accum_noise = 0;
124        self.sample_accum_dmc = 0;
125        self.sample_accum_exp = 0;
126        self.sample_accum_count = 0;
127        self.apu_subclock_even = false;
128    }
129
130    pub fn tick_cpu_cycle(&mut self) {
131        self.tick_frame_counter();
132        if self.apu_subclock_even {
133            self.pulse1.tick_timer();
134            self.pulse2.tick_timer();
135            self.noise.tick_timer();
136        }
137        self.apu_subclock_even = !self.apu_subclock_even;
138        self.triangle.tick_timer();
139        self.dmc.tick_timer();
140        if self.pending_dmc_dma.is_none() {
141            self.pending_dmc_dma = self.dmc.request_dma_if_needed();
142        }
143        if !self.expansions.is_empty() {
144            for chip in &mut self.expansions {
145                chip.tick_cpu_cycle();
146            }
147        }
148
149        // Fast path: skip mute mask checks when no channels are muted (common case)
150        let mask = self.debug_mute_mask;
151        let (p1, p2, tri, noise, dmc) = if mask == 0 {
152            (
153                self.pulse1.output(),
154                self.pulse2.output(),
155                self.triangle.output(),
156                self.noise.output(),
157                self.dmc.output_level,
158            )
159        } else {
160            (
161                if mask & 0x01 != 0 {
162                    0
163                } else {
164                    self.pulse1.output()
165                },
166                if mask & 0x02 != 0 {
167                    0
168                } else {
169                    self.pulse2.output()
170                },
171                if mask & 0x04 != 0 {
172                    0
173                } else {
174                    self.triangle.output()
175                },
176                if mask & 0x08 != 0 {
177                    0
178                } else {
179                    self.noise.output()
180                },
181                if mask & 0x10 != 0 {
182                    0
183                } else {
184                    self.dmc.output_level
185                },
186            )
187        };
188
189        // 使用整数累加器,避免每 CPU 周期的浮点运算
190        self.sample_accum_pulse += i64::from(p1 + p2);
191        self.sample_accum_tri += i64::from(tri);
192        self.sample_accum_noise += i64::from(noise);
193        self.sample_accum_dmc += i64::from(dmc);
194
195        if !self.expansions.is_empty() {
196            let mut exp_out = 0i64;
197            for chip in &self.expansions {
198                exp_out += (chip.output_sample() * 1000.0) as i64;
199            }
200            self.sample_accum_exp += exp_out;
201        }
202
203        self.sample_accum_count = self.sample_accum_count.saturating_add(1);
204
205        self.sample_phase_fixed += self.cycles_per_sample_fixed;
206        if self.sample_phase_fixed >= PHASE_SCALE {
207            self.sample_phase_fixed -= PHASE_SCALE;
208            let count = self.sample_accum_count.max(1);
209            // 只在输出时转换为浮点,使用乘法代替除法
210            let count_f64 = count as f64;
211            let inv_count = 1.0 / count_f64;
212            let avg_pulse = self.sample_accum_pulse as f64 * inv_count;
213            let avg_tri = self.sample_accum_tri as f64 * inv_count;
214            let avg_noise = self.sample_accum_noise as f64 * inv_count;
215            let avg_dmc = self.sample_accum_dmc as f64 * inv_count;
216            let avg_exp = self.sample_accum_exp as f64 * inv_count / 1000.0;
217
218            // 使用原始浮点混合公式
219            let pulse_mix = if avg_pulse > 0.0 {
220                (95.88 / ((8128.0 / avg_pulse) + 100.0)) as f32
221            } else {
222                0.0
223            };
224
225            let tnd_input = avg_tri / 8227.0 + avg_noise / 12241.0 + avg_dmc / 22638.0;
226            let tnd_mix = if tnd_input > 0.0 {
227                159.79 / ((1.0 / tnd_input) + 100.0)
228            } else {
229                0.0
230            };
231
232            let sample = (pulse_mix + tnd_mix as f32 + avg_exp as f32).clamp(-1.0, 1.0);
233
234            self.sample_accum_pulse = 0;
235            self.sample_accum_tri = 0;
236            self.sample_accum_noise = 0;
237            self.sample_accum_dmc = 0;
238            self.sample_accum_exp = 0;
239            self.sample_accum_count = 0;
240
241            self.audio_samples.push(sample);
242        }
243    }
244
245    pub fn read_status_at_offset(&mut self, _cycle_offset: u8) -> u8 {
246        let mut status = 0u8;
247        if self.pulse1.length_counter > 0 {
248            status |= 0x01;
249        }
250        if self.pulse2.length_counter > 0 {
251            status |= 0x02;
252        }
253        if self.triangle.length_counter > 0 {
254            status |= 0x04;
255        }
256        if self.noise.length_counter > 0 {
257            status |= 0x08;
258        }
259        if self.dmc.bytes_remaining > 0 {
260            status |= 0x10;
261        }
262        if self.frame_irq_flag {
263            status |= 0x40;
264        }
265        if self.dmc.irq_flag {
266            status |= 0x80;
267        }
268        self.frame_irq_flag = false;
269        status
270    }
271
272    pub fn write_register_at_offset(&mut self, addr: u16, data: u8, _cycle_offset: u8) {
273        match addr {
274            0x4000 => self.pulse1.write_control(data),
275            0x4001 => self.pulse1.write_sweep(data),
276            0x4002 => self.pulse1.write_timer_low(data),
277            0x4003 => self.pulse1.write_timer_high(data, self.pulse1.enabled),
278            0x4004 => self.pulse2.write_control(data),
279            0x4005 => self.pulse2.write_sweep(data),
280            0x4006 => self.pulse2.write_timer_low(data),
281            0x4007 => self.pulse2.write_timer_high(data, self.pulse2.enabled),
282            0x4008 => self.triangle.write_linear_control(data),
283            0x400A => self.triangle.write_timer_low(data),
284            0x400B => {
285                self.triangle.write_timer_high(data, self.triangle.enabled);
286            }
287            0x400C => self.noise.write_control(data),
288            0x400E => self.noise.write_period(data),
289            0x400F => self.noise.write_length(data, self.noise.enabled),
290            0x4010 => self.dmc.write_control(data),
291            0x4011 => self.dmc.write_output_level(data),
292            0x4012 => self.dmc.write_sample_address(data),
293            0x4013 => self.dmc.write_sample_length(data),
294            0x4015 => self.write_status(data),
295            0x4017 => self.write_frame_counter(data),
296            _ => {
297                for chip in &mut self.expansions {
298                    chip.cpu_write(addr, data);
299                }
300            }
301        }
302    }
303
304    pub fn sample_rate(&self) -> u32 {
305        self.sample_rate
306    }
307
308    pub fn set_sample_rate(&mut self, sample_rate: u32) {
309        if sample_rate == 0 || sample_rate == self.sample_rate {
310            return;
311        }
312
313        self.sample_rate = sample_rate;
314        self.cycles_per_sample_fixed = (PHASE_SCALE * sample_rate as u64) / CPU_CLOCK_NTSC;
315        self.sample_phase_fixed = 0;
316        self.sample_accum_pulse = 0;
317        self.sample_accum_tri = 0;
318        self.sample_accum_noise = 0;
319        self.sample_accum_dmc = 0;
320        self.sample_accum_exp = 0;
321        self.sample_accum_count = 0;
322        self.audio_samples.clear();
323    }
324
325    pub fn audio_samples(&self) -> &[f32] {
326        &self.audio_samples
327    }
328
329    pub fn clear_audio_samples(&mut self) {
330        self.audio_samples.clear();
331    }
332
333    pub fn irq_line(&self) -> bool {
334        self.frame_irq_flag
335            || self.dmc.irq_flag
336            || self.expansions.iter().any(|chip| chip.irq_line())
337    }
338
339    pub fn set_debug_mute_mask(&mut self, mask: u8) {
340        self.debug_mute_mask = mask & 0x1F;
341    }
342
343    pub fn debug_mute_mask(&self) -> u8 {
344        self.debug_mute_mask
345    }
346
347    pub fn take_dmc_dma_request(&mut self) -> Option<DmcDmaRequest> {
348        self.pending_dmc_dma.take()
349    }
350
351    pub fn submit_dmc_dma_sample(&mut self, data: u8) {
352        self.dmc.submit_dma_sample(data);
353    }
354
355    pub fn save_state(&self, writer: &mut StateWriter) {
356        writer.write_u8(self.pulse1.enabled as u8);
357        writer.write_u8(self.pulse1.length_counter);
358        writer.write_u8(self.pulse2.enabled as u8);
359        writer.write_u8(self.pulse2.length_counter);
360        writer.write_u8(self.triangle.enabled as u8);
361        writer.write_u8(self.triangle.length_counter);
362        writer.write_u8(self.noise.enabled as u8);
363        writer.write_u8(self.noise.length_counter);
364        writer.write_bool(self.frame_irq_inhibit);
365        writer.write_bool(self.frame_irq_flag);
366        writer.write_bool(self.frame_mode_five_step);
367        writer.write_u8(self.frame_step);
368        writer.write_u16(self.frame_divider);
369        writer.write_bool(self.dmc.enabled);
370        writer.write_bool(self.dmc.irq_enabled);
371        writer.write_bool(self.dmc.loop_flag);
372        writer.write_bool(self.dmc.irq_flag);
373        writer.write_u8(self.dmc.output_level);
374        writer.write_u16(self.dmc.sample_address);
375        writer.write_u16(self.dmc.sample_length);
376        writer.write_u16(self.dmc.current_address);
377        writer.write_u16(self.dmc.bytes_remaining);
378        writer.write_bool(self.dmc.silence);
379        writer.write_bool(self.apu_subclock_even);
380    }
381
382    pub fn load_state(&mut self, reader: &mut StateReader<'_>) -> Result<(), SaveStateError> {
383        self.pulse1.enabled = reader.read_u8()? != 0;
384        self.pulse1.length_counter = reader.read_u8()?;
385        self.pulse2.enabled = reader.read_u8()? != 0;
386        self.pulse2.length_counter = reader.read_u8()?;
387        self.triangle.enabled = reader.read_u8()? != 0;
388        self.triangle.length_counter = reader.read_u8()?;
389        self.noise.enabled = reader.read_u8()? != 0;
390        self.noise.length_counter = reader.read_u8()?;
391        self.frame_irq_inhibit = reader.read_bool()?;
392        self.frame_irq_flag = reader.read_bool()?;
393        self.frame_mode_five_step = reader.read_bool()?;
394        self.frame_step = reader.read_u8()?;
395        self.frame_divider = reader.read_u16()?;
396        self.dmc.enabled = reader.read_bool()?;
397        self.dmc.irq_enabled = reader.read_bool()?;
398        self.dmc.loop_flag = reader.read_bool()?;
399        self.dmc.irq_flag = reader.read_bool()?;
400        self.dmc.output_level = reader.read_u8()?;
401        self.dmc.sample_address = reader.read_u16()?;
402        self.dmc.sample_length = reader.read_u16()?;
403        self.dmc.current_address = reader.read_u16()?;
404        self.dmc.bytes_remaining = reader.read_u16()?;
405        self.dmc.silence = reader.read_bool()?;
406        self.apu_subclock_even = reader.read_bool()?;
407        self.pending_dmc_dma = None;
408        self.sample_accum_pulse = 0;
409        self.sample_accum_tri = 0;
410        self.sample_accum_noise = 0;
411        self.sample_accum_dmc = 0;
412        self.sample_accum_exp = 0;
413        self.sample_accum_count = 0;
414        Ok(())
415    }
416
417    fn write_status(&mut self, data: u8) {
418        self.pulse1.set_enabled((data & 0x01) != 0);
419        self.pulse2.set_enabled((data & 0x02) != 0);
420        self.triangle.set_enabled((data & 0x04) != 0);
421        self.noise.set_enabled((data & 0x08) != 0);
422        self.pending_dmc_dma = self.dmc.set_enabled((data & 0x10) != 0);
423        self.dmc.irq_flag = false;
424    }
425
426    fn write_frame_counter(&mut self, data: u8) {
427        self.frame_mode_five_step = (data & 0x80) != 0;
428        self.frame_irq_inhibit = (data & 0x40) != 0;
429        if self.frame_irq_inhibit {
430            self.frame_irq_flag = false;
431        }
432        self.frame_step = 0;
433        self.frame_divider = FRAME_SEQUENCER_DIVIDER + 8;
434
435        if self.frame_mode_five_step {
436            self.clock_quarter_frame();
437            self.clock_half_frame();
438        }
439    }
440
441    fn tick_frame_counter(&mut self) {
442        if self.frame_divider == 0 {
443            self.frame_divider = FRAME_SEQUENCER_DIVIDER;
444            self.clock_frame_step();
445        } else {
446            self.frame_divider -= 1;
447        }
448    }
449
450    fn clock_frame_step(&mut self) {
451        if !self.frame_mode_five_step {
452            self.clock_quarter_frame();
453            if self.frame_step == 1 || self.frame_step == 3 {
454                self.clock_half_frame();
455            }
456            if self.frame_step == 3 && !self.frame_irq_inhibit {
457                self.frame_irq_flag = true;
458            }
459            self.frame_step = (self.frame_step + 1) & 0x03;
460            return;
461        }
462
463        if self.frame_step != 3 {
464            self.clock_quarter_frame();
465        }
466        if self.frame_step == 1 || self.frame_step == 4 {
467            self.clock_half_frame();
468        }
469        self.frame_step = (self.frame_step + 1) % 5;
470    }
471
472    fn clock_quarter_frame(&mut self) {
473        self.pulse1.quarter_frame_tick();
474        self.pulse2.quarter_frame_tick();
475        self.triangle.quarter_frame_tick();
476        self.noise.quarter_frame_tick();
477        for chip in &mut self.expansions {
478            chip.clock_quarter_frame();
479        }
480    }
481
482    fn clock_half_frame(&mut self) {
483        self.pulse1.half_frame_tick();
484        self.pulse2.half_frame_tick();
485        self.triangle.half_frame_tick();
486        self.noise.half_frame_tick();
487        for chip in &mut self.expansions {
488            chip.clock_half_frame();
489        }
490    }
491}
492
493impl Default for APU {
494    fn default() -> Self {
495        Self::new()
496    }
497}
498
499#[cfg(test)]
500mod tests;