channel 4 mem interface + ditch apu ram array
This commit is contained in:
parent
83080ed806
commit
9f9cd006c0
|
@ -1,10 +1,6 @@
|
||||||
use self::types::{Channels, DacSample, Mixer, VinEnable, Volume};
|
use self::types::{Channels, DacSample, Mixer, VinEnable, Volume};
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::{
|
processor::{memory::Address, timer::CLOCK_SPEED, Cpu},
|
||||||
memory::{masked_update, Address},
|
|
||||||
timer::CLOCK_SPEED,
|
|
||||||
Cpu,
|
|
||||||
},
|
|
||||||
util::{get_bit, set_or_clear_bit},
|
util::{get_bit, set_or_clear_bit},
|
||||||
};
|
};
|
||||||
use async_ringbuf::{AsyncHeapProducer, AsyncHeapRb};
|
use async_ringbuf::{AsyncHeapProducer, AsyncHeapRb};
|
||||||
|
@ -19,13 +15,6 @@ use samplerate::{ConverterType, Samplerate};
|
||||||
mod channels;
|
mod channels;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
const MEM_START: usize = 0xFF10;
|
|
||||||
const MEM_SIZE: usize = 0xFF40 - MEM_START;
|
|
||||||
|
|
||||||
const fn reg(a: Address) -> usize {
|
|
||||||
(a as usize) - MEM_START
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DacSample {
|
impl DacSample {
|
||||||
fn mixed(&self, mixer: &Mixer) -> Vec<f32> {
|
fn mixed(&self, mixer: &Mixer) -> Vec<f32> {
|
||||||
let left = (self.one * mixer.ch1.left.scale())
|
let left = (self.one * mixer.ch1.left.scale())
|
||||||
|
@ -46,7 +35,6 @@ impl DacSample {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Apu {
|
pub struct Apu {
|
||||||
mem: [u8; MEM_SIZE],
|
|
||||||
apu_enable: bool,
|
apu_enable: bool,
|
||||||
channels: Channels,
|
channels: Channels,
|
||||||
vin: VinEnable,
|
vin: VinEnable,
|
||||||
|
@ -87,7 +75,6 @@ impl Default for Apu {
|
||||||
let config = config.config();
|
let config = config.config();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mem: [0x0; MEM_SIZE],
|
|
||||||
apu_enable: true,
|
apu_enable: true,
|
||||||
channels: Channels::default(),
|
channels: Channels::default(),
|
||||||
vin: VinEnable::default(),
|
vin: VinEnable::default(),
|
||||||
|
@ -196,7 +183,7 @@ impl Apu {
|
||||||
|| addr == 0xFF16
|
|| addr == 0xFF16
|
||||||
|| addr == 0xFF1B
|
|| addr == 0xFF1B
|
||||||
|| addr == 0xFF20
|
|| addr == 0xFF20
|
||||||
|| get_bit(self.mem[reg(0xFF26)], 7)
|
|| self.apu_enable
|
||||||
{
|
{
|
||||||
self.make_register(addr)
|
self.make_register(addr)
|
||||||
} else {
|
} else {
|
||||||
|
@ -216,6 +203,9 @@ impl Apu {
|
||||||
0xFF1A => self.channels.three.get_dac(),
|
0xFF1A => self.channels.three.get_dac(),
|
||||||
0xFF1C => self.channels.three.get_volume(),
|
0xFF1C => self.channels.three.get_volume(),
|
||||||
0xFF1E => self.channels.three.get_control(),
|
0xFF1E => self.channels.three.get_control(),
|
||||||
|
0xFF21 => self.channels.four.get_volume_and_envelope(),
|
||||||
|
0xFF22 => self.channels.four.get_frequency_and_randomness(),
|
||||||
|
0xFF23 => self.channels.four.get_control(),
|
||||||
0xFF24 => {
|
0xFF24 => {
|
||||||
// NR50 - Master volume + VIN panning
|
// NR50 - Master volume + VIN panning
|
||||||
let mut v =
|
let mut v =
|
||||||
|
@ -253,7 +243,6 @@ impl Apu {
|
||||||
// wave ram
|
// wave ram
|
||||||
0xFF30..0xFF40 => 0xFF,
|
0xFF30..0xFF40 => 0xFF,
|
||||||
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
|
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
|
||||||
_ => self.mem[reg(addr)],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,10 +262,10 @@ impl Apu {
|
||||||
0xFF1C => self.channels.three.update_volume(data),
|
0xFF1C => self.channels.three.update_volume(data),
|
||||||
0xFF1D => self.channels.three.update_wavelength_low(data),
|
0xFF1D => self.channels.three.update_wavelength_low(data),
|
||||||
0xFF1E => self.channels.three.update_wavelength_high_and_control(data),
|
0xFF1E => self.channels.three.update_wavelength_high_and_control(data),
|
||||||
0xFF20 => self.masked_io(reg(addr), data, 0b111111),
|
0xFF20 => self.channels.four.update_length_timer(data),
|
||||||
0xFF23 => {
|
0xFF21 => self.channels.four.update_volume_and_envelope(data),
|
||||||
self.mem[reg(addr)] = (self.mem[reg(addr)] & 0b10111111) | (data & 0b01000000)
|
0xFF22 => self.channels.four.update_frequency_and_randomness(data),
|
||||||
}
|
0xFF23 => self.channels.four.update_control(data),
|
||||||
0xFF24 => {
|
0xFF24 => {
|
||||||
self.vin.left = get_bit(data, 7);
|
self.vin.left = get_bit(data, 7);
|
||||||
self.vin.right = get_bit(data, 3);
|
self.vin.right = get_bit(data, 3);
|
||||||
|
@ -295,14 +284,10 @@ impl Apu {
|
||||||
}
|
}
|
||||||
0xFF26 => self.apu_enable = (1 << 7) == (data & 0b10000000),
|
0xFF26 => self.apu_enable = (1 << 7) == (data & 0b10000000),
|
||||||
0xFF30..0xFF40 => self.channels.three.update_wave_ram(addr, data),
|
0xFF30..0xFF40 => self.channels.three.update_wave_ram(addr, data),
|
||||||
0xFF11..0xFF1A | 0xFF1D..0xFF23 | 0xFF24..0xFF30 => self.mem[reg(addr)] = data,
|
0xFF15 | 0xFF1F | 0xFF27..0xFF30 => {}
|
||||||
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
|
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn masked_io(&mut self, addr_el: usize, data: u8, mask: u8) {
|
|
||||||
self.mem[addr_el] = masked_update(self.mem[addr_el], data, mask);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
|
|
|
@ -441,12 +441,105 @@ impl WaveChannel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum LfsrWidth {
|
||||||
|
FifteenBit,
|
||||||
|
SevenBit,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Lfsr {
|
||||||
|
clock_shift: u8,
|
||||||
|
width: LfsrWidth,
|
||||||
|
clock_divider: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Lfsr {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
clock_shift: Default::default(),
|
||||||
|
width: LfsrWidth::FifteenBit,
|
||||||
|
clock_divider: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct NoiseChannel {
|
pub(super) struct NoiseChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
|
length_enable: bool,
|
||||||
|
length_timer: u8,
|
||||||
|
envelope: Envelope,
|
||||||
|
queued_envelope: Envelope,
|
||||||
|
lfsr: Lfsr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoiseChannel {
|
impl NoiseChannel {
|
||||||
pub(super) fn new(enabled: bool) -> Self {
|
pub(super) fn new(enabled: bool) -> Self {
|
||||||
Self { enabled }
|
Self {
|
||||||
|
enabled,
|
||||||
|
length_enable: false,
|
||||||
|
length_timer: 0,
|
||||||
|
envelope: Envelope::default(),
|
||||||
|
queued_envelope: Envelope::default(),
|
||||||
|
lfsr: Lfsr::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger(&mut self) {
|
||||||
|
self.enabled = true;
|
||||||
|
self.envelope = self.queued_envelope;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn update_length_timer(&mut self, data: u8) {
|
||||||
|
self.length_timer = data & 0b111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn update_volume_and_envelope(&mut self, data: u8) {
|
||||||
|
self.queued_envelope = Envelope::new(
|
||||||
|
(data & 0b11110000) >> 4,
|
||||||
|
if (data & 0b1000) == 0b1000 {
|
||||||
|
EnvelopeMode::Increase
|
||||||
|
} else {
|
||||||
|
EnvelopeMode::Decrease
|
||||||
|
},
|
||||||
|
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_frequency_and_randomness(&mut self, data: u8) {
|
||||||
|
self.lfsr.clock_shift = (data & 0b11110000) >> 4;
|
||||||
|
self.lfsr.width = if get_bit(data, 3) {
|
||||||
|
LfsrWidth::SevenBit
|
||||||
|
} else {
|
||||||
|
LfsrWidth::FifteenBit
|
||||||
|
};
|
||||||
|
self.lfsr.clock_divider = data & 0b111;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_frequency_and_randomness(&self) -> u8 {
|
||||||
|
set_or_clear_bit(
|
||||||
|
self.lfsr.clock_shift << 4 | self.lfsr.clock_divider,
|
||||||
|
3,
|
||||||
|
self.lfsr.width == LfsrWidth::SevenBit,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn update_control(&mut self, data: u8) {
|
||||||
|
if get_bit(data, 7) {
|
||||||
|
self.trigger();
|
||||||
|
}
|
||||||
|
self.length_enable = get_bit(data, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_control(&self) -> u8 {
|
||||||
|
set_or_clear_bit(0xFF, 6, self.length_enable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue