Skip to content

Commit

Permalink
Merge pull request #44 from YushiOMOTE/refactor-apu
Browse files Browse the repository at this point in the history
Refactor apu
  • Loading branch information
YushiOMOTE authored Jul 25, 2024
2 parents 7c60de6 + bb92cfb commit 2d3c360
Show file tree
Hide file tree
Showing 12 changed files with 648 additions and 337 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ lazy_static = { version = "1.2", features = ["spin_no_std"] }
log = "0.4"
hashbrown = "0.14"
spin = "0.9"
bitfield-struct = "0.8.0"

[dev-dependencies]
env_logger = "0.11"
Expand Down
105 changes: 68 additions & 37 deletions core/src/apu/mixer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,52 @@ use super::{
};
use crate::hardware::Stream;
use alloc::sync::Arc;
use bitfield_struct::bitfield;
use core::sync::atomic::{AtomicBool, AtomicUsize};
use spin::Mutex;

pub struct Mixer {
power: bool,
ctrl: u8,
so1_volume: usize,
so2_volume: usize,
so_mask: usize,
enable: bool,
nr50: Nr50,
nr51: Nr51,
stream: MixerStream,
}

#[bitfield(u8)]
struct Nr50 {
#[bits(3)]
right_volume: usize,
vin_right_enable: bool,
#[bits(3)]
left_volume: usize,
vin_left_enable: bool,
}

#[bitfield(u8)]
struct Nr51 {
ch1_right: bool,
ch2_right: bool,
ch3_right: bool,
ch4_right: bool,
ch1_left: bool,
ch2_left: bool,
ch3_left: bool,
ch4_left: bool,
}

impl Mixer {
pub fn new() -> Self {
Self {
power: false,
ctrl: 0,
so1_volume: 0,
so2_volume: 0,
so_mask: 0,
enable: false,
nr50: Nr50::default(),
nr51: Nr51::default(),
stream: MixerStream::new(),
}
}

/// Read NR50 register (0xff24)
pub fn read_ctrl(&self) -> u8 {
self.ctrl
self.nr50.into_bits()
}

/// Write NR50 register (0xff24)
Expand All @@ -43,15 +60,14 @@ impl Mixer {
return;
}

self.ctrl = value;
self.so1_volume = (value as usize & 0x70) >> 4;
self.so2_volume = value as usize & 0x07;
self.nr50 = Nr50::from_bits(value);

self.update_stream();
}

/// Read NR51 register (0xff25)
pub fn read_so_mask(&self) -> u8 {
self.so_mask as u8
self.nr51.into_bits()
}

/// Write NR51 register (0xff25)
Expand All @@ -60,7 +76,8 @@ impl Mixer {
return;
}

self.so_mask = value as usize;
self.nr51 = Nr51::from_bits(value);

self.update_stream();
}

Expand All @@ -82,54 +99,68 @@ impl Mixer {
self.stream.clone()
}

pub fn enable(&mut self, enable: bool) {
self.enable = enable;
self.update_stream();
}

// Update streams based on register settings
fn update_stream(&mut self) {
self.stream.enable.set(self.enable);
self.stream.enable.set(self.power);

if self.enable {
if self.power {
for (i, tone) in self.stream.tones.iter().enumerate() {
tone.volume.set(self.get_volume(i as u8))
tone.volume.set(self.get_tone_volume(i))
}
self.stream.wave.volume.set(self.get_volume(2));
self.stream.noise.volume.set(self.get_volume(3));
self.stream.wave.volume.set(self.get_wave_volume());
self.stream.noise.volume.set(self.get_noise_volume());
}
}

fn get_volume(&self, id: u8) -> usize {
let mask = 1 << id;
let v1 = if self.so_mask & mask != 0 {
self.so1_volume
fn get_tone_volume(&self, tone: usize) -> usize {
if tone == 0 {
self.get_volume(self.nr51.ch1_right(), self.nr51.ch1_left())
} else {
self.get_volume(self.nr51.ch2_right(), self.nr51.ch2_left())
}
}

fn get_wave_volume(&self) -> usize {
self.get_volume(self.nr51.ch3_right(), self.nr51.ch3_left())
}

fn get_noise_volume(&self) -> usize {
self.get_volume(self.nr51.ch4_right(), self.nr51.ch4_left())
}

fn get_volume(&self, right_enable: bool, left_enable: bool) -> usize {
let right = if right_enable {
self.nr50.right_volume()
} else {
0
};
let v2 = if self.so_mask & (mask << 4) != 0 {
self.so2_volume

let left = if left_enable {
self.nr50.left_volume()
} else {
0
};
v1 + v2

right + left
}

pub fn power_on(&mut self) {
self.power = true;
self.update_stream();
}

pub fn power_off(&mut self) {
self.power = false;
self.ctrl = 0;
self.so1_volume = 0;
self.so2_volume = 0;
self.so_mask = 0;

self.nr50 = Nr50::default();
self.nr51 = Nr51::default();

for tone in &mut self.stream.tones {
tone.clear();
}
self.stream.wave.clear();
self.stream.noise.clear();
self.update_stream();
}
}

Expand Down
52 changes: 28 additions & 24 deletions core/src/apu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::hardware::HardwareHandle;

use self::{mixer::Mixer, noise::Noise, tone::Tone, wave::Wave};

use bitfield_struct::bitfield;

mod clock_divider;
mod frame_sequencer;
mod length_counter;
Expand All @@ -23,7 +25,18 @@ pub struct Apu {
wave: Wave,
noise: Noise,
mixer: Mixer,
enable: bool,
nr52: Nr52,
}

#[bitfield(u8)]
struct Nr52 {
ch1_on: bool,
ch2_on: bool,
ch3_on: bool,
ch4_on: bool,
#[bits(3)]
_unused: u8,
power_on: bool,
}

impl Apu {
Expand All @@ -39,7 +52,7 @@ impl Apu {
wave: Wave::new(),
noise: Noise::new(),
mixer,
enable: false,
nr52: Nr52::default(),
}
}

Expand Down Expand Up @@ -226,40 +239,33 @@ impl Apu {

/// Read NR52 register (0xff26)
pub fn read_enable(&self) -> u8 {
let mut v = 0x70;
v |= if self.enable { 0x80 } else { 0x00 };
v |= if self.tones[0].is_active() {
0x01
} else {
0x00
};
v |= if self.tones[1].is_active() {
0x02
} else {
0x00
};
v |= if self.wave.is_active() { 0x04 } else { 0x00 };
v |= if self.noise.is_active() { 0x08 } else { 0x00 };
v
self.nr52
.with_ch1_on(self.tones[0].is_active())
.with_ch2_on(self.tones[1].is_active())
.with_ch3_on(self.wave.is_active())
.with_ch4_on(self.noise.is_active())
.into_bits()
| 0x70
}

/// Write NR52 register (0xff26)
pub fn write_enable(&mut self, value: u8) {
debug!("Write NR52: {:02x}", value);
let before = self.nr52.power_on();

let enable = value & 0x80 != 0;
self.nr52 = Nr52::from_bits(value);

self.mixer.enable(enable);
let after = self.nr52.power_on();

if !self.enable && enable {
if !before && after {
info!("Sound master enabled");
for tone in &mut self.tones {
tone.power_on();
}

self.wave.power_on();
self.noise.power_on();
self.mixer.power_on();
} else if self.enable && !enable {
} else if before && !after {
info!("Sound master disabled");

for tone in &mut self.tones {
Expand All @@ -269,8 +275,6 @@ impl Apu {
self.noise.power_off();
self.mixer.power_off();
}

self.enable = enable;
}

pub fn step(&mut self, cycles: usize) {
Expand Down
Loading

0 comments on commit 2d3c360

Please sign in to comment.