pwm registers enabled

This commit is contained in:
Alex Janka 2023-02-14 08:12:14 +11:00
parent 6f5a1c648c
commit 645b5e365a
2 changed files with 204 additions and 25 deletions

View file

@ -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),

View 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,
}
}
}