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