pwm registers enabled
This commit is contained in:
parent
6f5a1c648c
commit
645b5e365a
|
@ -3,6 +3,10 @@ use crate::{
|
|||
util::{get_bit, set_or_clear_bit},
|
||||
};
|
||||
|
||||
use self::channels::{EnvelopeMode, NoiseChannel, PwmChannel, WaveChannel};
|
||||
|
||||
mod channels;
|
||||
|
||||
const MEM_START: usize = 0xFF10;
|
||||
const MEM_SIZE: usize = 0xFF40 - MEM_START;
|
||||
|
||||
|
@ -10,36 +14,20 @@ const fn reg(a: Address) -> usize {
|
|||
(a as usize) - MEM_START
|
||||
}
|
||||
|
||||
struct Channel {
|
||||
enabled: bool,
|
||||
pan_left: bool,
|
||||
pan_right: bool,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
|
||||
Self {
|
||||
enabled,
|
||||
pan_left,
|
||||
pan_right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Channels {
|
||||
one: Channel,
|
||||
two: Channel,
|
||||
three: Channel,
|
||||
four: Channel,
|
||||
one: PwmChannel,
|
||||
two: PwmChannel,
|
||||
three: WaveChannel,
|
||||
four: NoiseChannel,
|
||||
}
|
||||
|
||||
impl Default for Channels {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
one: Channel::new(true, true, true),
|
||||
two: Channel::new(false, true, true),
|
||||
three: Channel::new(false, true, false),
|
||||
four: Channel::new(false, true, false),
|
||||
one: PwmChannel::new(true, true, true),
|
||||
two: PwmChannel::new(false, true, true),
|
||||
three: WaveChannel::new(false, true, false),
|
||||
four: NoiseChannel::new(false, true, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +77,13 @@ impl Apu {
|
|||
|
||||
fn make_register(&self, addr: Address) -> u8 {
|
||||
match addr {
|
||||
0xFF10 => self.channels.one.get_sweep_register(),
|
||||
0xFF11 => self.channels.one.get_length_timer_and_duty_cycle(),
|
||||
0xFF12 => self.channels.one.get_volume_and_envelope(),
|
||||
0xFF14 => self.channels.one.get_control(),
|
||||
0xFF16 => self.channels.two.get_length_timer_and_duty_cycle(),
|
||||
0xFF17 => self.channels.two.get_volume_and_envelope(),
|
||||
0xFF19 => self.channels.two.get_control(),
|
||||
0xFF24 => {
|
||||
// NR50 - Master volume + VIN panning
|
||||
let mut v = ((self.vol_left << 4) & 0b1110000) | (self.vol_right & 0b111);
|
||||
|
@ -129,7 +124,24 @@ impl Apu {
|
|||
|
||||
pub fn mmio_write(&mut self, addr: Address, data: u8) {
|
||||
match addr {
|
||||
0xFF10 => self.masked_io(reg(addr), data, 0b01111111),
|
||||
0xFF10 => {
|
||||
let pace = (data & 0b1110000) >> 4;
|
||||
let mode = if get_bit(data, 3) {
|
||||
EnvelopeMode::Decrease
|
||||
} else {
|
||||
EnvelopeMode::Increase
|
||||
};
|
||||
let slope = data & 0b111;
|
||||
self.channels.one.update_sweep(pace, mode, slope);
|
||||
}
|
||||
0xFF11 => self.channels.one.update_length_timer_and_duty_cycle(data),
|
||||
0xFF12 => self.channels.one.update_volume_and_envelope(data),
|
||||
0xFF13 => self.channels.one.update_wavelength_low(data),
|
||||
0xFF14 => self.channels.one.update_wavelength_high_and_control(data),
|
||||
0xFF16 => self.channels.two.update_length_timer_and_duty_cycle(data),
|
||||
0xFF17 => self.channels.two.update_volume_and_envelope(data),
|
||||
0xFF18 => self.channels.two.update_wavelength_low(data),
|
||||
0xFF19 => self.channels.two.update_wavelength_high_and_control(data),
|
||||
0xFF1A => self.masked_io(reg(addr), data, 0b10000000),
|
||||
0xFF1C => self.masked_io(reg(addr), data, 0b1100000),
|
||||
0xFF20 => self.masked_io(reg(addr), data, 0b111111),
|
||||
|
|
167
src/processor/memory/mmio/apu/channels.rs
Normal file
167
src/processor/memory/mmio/apu/channels.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use crate::util::{get_bit, set_or_clear_bit};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub(super) enum EnvelopeMode {
|
||||
Increase,
|
||||
Decrease,
|
||||
}
|
||||
|
||||
struct Sweep {
|
||||
pace: u8,
|
||||
mode: EnvelopeMode,
|
||||
slope: u8,
|
||||
}
|
||||
|
||||
impl Default for Sweep {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pace: 0,
|
||||
mode: EnvelopeMode::Increase,
|
||||
slope: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
struct Envelope {
|
||||
initial_volume: u8,
|
||||
mode: EnvelopeMode,
|
||||
rate: u8,
|
||||
}
|
||||
|
||||
impl Default for Envelope {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
initial_volume: 0xF,
|
||||
mode: EnvelopeMode::Decrease,
|
||||
rate: 0x3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct PwmChannel {
|
||||
pub(super) enabled: bool,
|
||||
pub(super) pan_left: bool,
|
||||
pub(super) pan_right: bool,
|
||||
sweep: Sweep,
|
||||
duty_cycle: u8,
|
||||
length_enable: bool,
|
||||
length_timer: u8,
|
||||
envelope: Envelope,
|
||||
queued_envelope: Envelope,
|
||||
wavelength: u16,
|
||||
}
|
||||
|
||||
impl PwmChannel {
|
||||
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
|
||||
Self {
|
||||
enabled,
|
||||
pan_left,
|
||||
pan_right,
|
||||
sweep: Sweep::default(),
|
||||
duty_cycle: 2,
|
||||
length_enable: false,
|
||||
length_timer: 63,
|
||||
envelope: Envelope::default(),
|
||||
queued_envelope: Envelope::default(),
|
||||
wavelength: 0x700,
|
||||
}
|
||||
}
|
||||
|
||||
fn trigger(&mut self) {
|
||||
self.enabled = true;
|
||||
self.envelope = self.queued_envelope;
|
||||
}
|
||||
|
||||
pub(super) fn update_sweep(&mut self, pace: u8, mode: EnvelopeMode, slope: u8) {
|
||||
self.sweep.pace = pace;
|
||||
self.sweep.mode = mode;
|
||||
self.sweep.slope = slope;
|
||||
}
|
||||
|
||||
pub(super) fn get_sweep_register(&self) -> u8 {
|
||||
set_or_clear_bit(
|
||||
((self.sweep.pace & 0b1110000) << 4) | (self.sweep.slope & 0b111),
|
||||
3,
|
||||
self.sweep.mode == EnvelopeMode::Decrease,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn update_length_timer_and_duty_cycle(&mut self, data: u8) {
|
||||
self.length_timer = (data & 0b11000000) >> 6;
|
||||
self.duty_cycle = data & 0b11111;
|
||||
}
|
||||
|
||||
pub(super) fn get_length_timer_and_duty_cycle(&self) -> u8 {
|
||||
((self.duty_cycle & 0b11) << 6) | 0b11111
|
||||
}
|
||||
|
||||
pub(super) fn update_volume_and_envelope(&mut self, data: u8) {
|
||||
self.queued_envelope = Envelope {
|
||||
initial_volume: (data & 0b11110000) >> 4,
|
||||
mode: if (data & 0b1000) == 0b1000 {
|
||||
EnvelopeMode::Increase
|
||||
} else {
|
||||
EnvelopeMode::Decrease
|
||||
},
|
||||
rate: data & 0b111,
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) fn get_volume_and_envelope(&self) -> u8 {
|
||||
set_or_clear_bit(
|
||||
(self.queued_envelope.rate & 0b111)
|
||||
| ((self.queued_envelope.initial_volume & 0b1111) << 4),
|
||||
3,
|
||||
self.queued_envelope.mode == EnvelopeMode::Decrease,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn update_wavelength_low(&mut self, data: u8) {
|
||||
self.wavelength = (self.wavelength & 0xFF00) | (data as u16);
|
||||
}
|
||||
|
||||
pub(super) fn update_wavelength_high_and_control(&mut self, data: u8) {
|
||||
self.length_enable = get_bit(data, 6);
|
||||
self.wavelength = (self.wavelength & 0xFF) | (((data & 0b111) as u16) << 8);
|
||||
if get_bit(data, 7) {
|
||||
self.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_control(&self) -> u8 {
|
||||
set_or_clear_bit(0, 6, self.length_enable)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct WaveChannel {
|
||||
pub(super) enabled: bool,
|
||||
pub(super) pan_left: bool,
|
||||
pub(super) pan_right: bool,
|
||||
}
|
||||
|
||||
impl WaveChannel {
|
||||
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
|
||||
Self {
|
||||
enabled,
|
||||
pan_left,
|
||||
pan_right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct NoiseChannel {
|
||||
pub(super) enabled: bool,
|
||||
pub(super) pan_left: bool,
|
||||
pub(super) pan_right: bool,
|
||||
}
|
||||
|
||||
impl NoiseChannel {
|
||||
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
|
||||
Self {
|
||||
enabled,
|
||||
pan_left,
|
||||
pan_right,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue