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