Compare commits
2 Commits
9e36e86c14
...
c7e3cb5b35
Author | SHA1 | Date |
---|---|---|
Rekai Nyangadzayi Musuka | c7e3cb5b35 | |
Rekai Nyangadzayi Musuka | e4d77d66ba |
86
src/apu.rs
86
src/apu.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::bus::BusIo;
|
||||||
use crate::emu::SM83_CLOCK_SPEED;
|
use crate::emu::SM83_CLOCK_SPEED;
|
||||||
use gen::{AudioBuffer, AudioSender};
|
use gen::{AudioBuffer, AudioSender};
|
||||||
use types::ch1::{Sweep, SweepDirection};
|
use types::ch1::{Sweep, SweepDirection};
|
||||||
|
@ -18,15 +19,15 @@ const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct Apu {
|
pub struct Apu {
|
||||||
pub(crate) ctrl: SoundControl,
|
ctrl: SoundControl,
|
||||||
/// Tone & Sweep
|
/// Tone & Sweep
|
||||||
pub(crate) ch1: Channel1,
|
ch1: Channel1,
|
||||||
/// Tone
|
/// Tone
|
||||||
pub(crate) ch2: Channel2,
|
ch2: Channel2,
|
||||||
/// Wave
|
/// Wave
|
||||||
pub(crate) ch3: Channel3,
|
ch3: Channel3,
|
||||||
/// Noise
|
/// Noise
|
||||||
pub(crate) ch4: Channel4,
|
ch4: Channel4,
|
||||||
|
|
||||||
// Frame Sequencer
|
// Frame Sequencer
|
||||||
frame_seq_state: FrameSequencerState,
|
frame_seq_state: FrameSequencerState,
|
||||||
|
@ -38,6 +39,66 @@ pub struct Apu {
|
||||||
buffer: AudioBuffer<(f32, f32)>,
|
buffer: AudioBuffer<(f32, f32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BusIo for Apu {
|
||||||
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
|
match addr & 0x00FF {
|
||||||
|
0x11 => self.ch1.duty(),
|
||||||
|
0x12 => self.ch1.envelope(),
|
||||||
|
0x14 => self.ch1.freq_hi(),
|
||||||
|
0x16 => self.ch2.duty(),
|
||||||
|
0x17 => self.ch2.envelope(),
|
||||||
|
0x19 => self.ch2.freq_hi(),
|
||||||
|
0x1A => self.ch3.enabled(),
|
||||||
|
0x1B => self.ch3.len(),
|
||||||
|
0x1C => self.ch3.volume(),
|
||||||
|
0x1E => self.ch3.freq_hi(),
|
||||||
|
0x20 => self.ch4.len(),
|
||||||
|
0x21 => self.ch4.envelope(),
|
||||||
|
0x22 => self.ch4.poly(),
|
||||||
|
0x23 => self.ch4.frequency(),
|
||||||
|
0x24 => self.ctrl.channel(),
|
||||||
|
0x25 => self.ctrl.output(),
|
||||||
|
0x26 => self.ctrl.status(self),
|
||||||
|
0x30..=0x3F => self.ch3.read_byte(addr),
|
||||||
|
_ => {
|
||||||
|
eprintln!("Read 0xFF from unused IO register {:#06X} [APU]", addr);
|
||||||
|
0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
|
match addr & 0x00FF {
|
||||||
|
0x10 => self.ch1.set_sweep(byte),
|
||||||
|
0x11 => self.ch1.set_duty(byte),
|
||||||
|
0x12 => self.ch1.set_envelope(byte),
|
||||||
|
0x13 => self.ch1.set_freq_lo(byte),
|
||||||
|
0x14 => self.ch1.set_freq_hi(byte),
|
||||||
|
0x16 => self.ch2.set_duty(byte),
|
||||||
|
0x17 => self.ch2.set_envelope(byte),
|
||||||
|
0x18 => self.ch2.set_freq_lo(byte),
|
||||||
|
0x19 => self.ch2.set_freq_hi(byte),
|
||||||
|
0x1A => self.ch3.set_enabled(byte),
|
||||||
|
0x1B => self.ch3.set_len(byte),
|
||||||
|
0x1C => self.ch3.set_volume(byte),
|
||||||
|
0x1D => self.ch3.set_freq_lo(byte),
|
||||||
|
0x1E => self.ch3.set_freq_hi(byte),
|
||||||
|
0x20 => self.ch4.set_len(byte),
|
||||||
|
0x21 => self.ch4.set_envelope(byte),
|
||||||
|
0x22 => self.ch4.set_poly(byte),
|
||||||
|
0x23 => self.ch4.set_freq_data(byte),
|
||||||
|
0x24 => self.ctrl.set_channel(byte),
|
||||||
|
0x25 => self.ctrl.set_output(byte),
|
||||||
|
0x26 => self.set_status(byte),
|
||||||
|
0x30..=0x3F => self.ch3.write_byte(addr, byte),
|
||||||
|
_ => eprintln!(
|
||||||
|
"Wrote {:#04X} to unused IO register {:#06X} [APU]",
|
||||||
|
byte, addr
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Apu {
|
impl Apu {
|
||||||
pub(crate) fn clock(&mut self, div: u16) {
|
pub(crate) fn clock(&mut self, div: u16) {
|
||||||
use FrameSequencerState::*;
|
use FrameSequencerState::*;
|
||||||
|
@ -611,7 +672,8 @@ pub(crate) struct Channel3 {
|
||||||
freq_lo: u8,
|
freq_lo: u8,
|
||||||
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
||||||
freq_hi: FrequencyHigh,
|
freq_hi: FrequencyHigh,
|
||||||
pub(crate) wave_ram: [u8; WAVE_PATTERN_RAM_LEN],
|
|
||||||
|
wave_ram: [u8; WAVE_PATTERN_RAM_LEN],
|
||||||
|
|
||||||
// Length Functionality
|
// Length Functionality
|
||||||
length_timer: u16,
|
length_timer: u16,
|
||||||
|
@ -620,7 +682,19 @@ pub(crate) struct Channel3 {
|
||||||
offset: u8,
|
offset: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BusIo for Channel3 {
|
||||||
|
fn read_byte(&self, addr: u16) -> u8 {
|
||||||
|
self.wave_ram[(addr - Self::WAVE_RAM_START_ADDR) as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
|
self.wave_ram[(addr - Self::WAVE_RAM_START_ADDR) as usize] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Channel3 {
|
impl Channel3 {
|
||||||
|
const WAVE_RAM_START_ADDR: u16 = 0xFF30;
|
||||||
|
|
||||||
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
pub(crate) fn enabled(&self) -> u8 {
|
pub(crate) fn enabled(&self) -> u8 {
|
||||||
((self.enabled as u8) << 7) | 0x7F
|
((self.enabled as u8) << 7) | 0x7F
|
||||||
|
|
45
src/bus.rs
45
src/bus.rs
|
@ -224,25 +224,7 @@ impl BusIo for Bus {
|
||||||
0x06 => self.timer.modulo,
|
0x06 => self.timer.modulo,
|
||||||
0x07 => self.timer.ctrl.into(),
|
0x07 => self.timer.ctrl.into(),
|
||||||
0x0F => self.interrupt_flag().into(),
|
0x0F => self.interrupt_flag().into(),
|
||||||
0x10 => self.apu.ch1.sweep(),
|
0x10..=0x3F => self.apu.read_byte(addr),
|
||||||
0x11 => self.apu.ch1.duty(),
|
|
||||||
0x12 => self.apu.ch1.envelope(),
|
|
||||||
0x14 => self.apu.ch1.freq_hi(),
|
|
||||||
0x16 => self.apu.ch2.duty(),
|
|
||||||
0x17 => self.apu.ch2.envelope(),
|
|
||||||
0x19 => self.apu.ch2.freq_hi(),
|
|
||||||
0x1A => self.apu.ch3.enabled(),
|
|
||||||
0x1B => self.apu.ch3.len(),
|
|
||||||
0x1C => self.apu.ch3.volume(),
|
|
||||||
0x1E => self.apu.ch3.freq_hi(),
|
|
||||||
0x20 => self.apu.ch4.len(),
|
|
||||||
0x21 => self.apu.ch4.envelope(),
|
|
||||||
0x22 => self.apu.ch4.poly(),
|
|
||||||
0x23 => self.apu.ch4.frequency(),
|
|
||||||
0x24 => self.apu.ctrl.channel(),
|
|
||||||
0x25 => self.apu.ctrl.output(),
|
|
||||||
0x26 => self.apu.ctrl.status(&self.apu),
|
|
||||||
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30],
|
|
||||||
0x40 => self.ppu.ctrl.into(),
|
0x40 => self.ppu.ctrl.into(),
|
||||||
0x41 => self.ppu.stat.into(),
|
0x41 => self.ppu.stat.into(),
|
||||||
0x42 => self.ppu.pos.scroll_y,
|
0x42 => self.ppu.pos.scroll_y,
|
||||||
|
@ -255,7 +237,7 @@ impl BusIo for Bus {
|
||||||
0x49 => self.ppu.monochrome.obj_palette_1.into(),
|
0x49 => self.ppu.monochrome.obj_palette_1.into(),
|
||||||
0x4A => self.ppu.pos.window_y,
|
0x4A => self.ppu.pos.window_y,
|
||||||
0x4B => self.ppu.pos.window_x,
|
0x4B => self.ppu.pos.window_x,
|
||||||
0x4D => 0xFF, // CGB Specific Register
|
0x4D => 0xFF, // TODO: CGB Specific Register
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("Read 0xFF from unused IO register {:#06X}.", addr);
|
eprintln!("Read 0xFF from unused IO register {:#06X}.", addr);
|
||||||
0xFF
|
0xFF
|
||||||
|
@ -342,28 +324,7 @@ impl BusIo for Bus {
|
||||||
0x06 => self.timer.modulo = byte,
|
0x06 => self.timer.modulo = byte,
|
||||||
0x07 => self.timer.ctrl = byte.into(),
|
0x07 => self.timer.ctrl = byte.into(),
|
||||||
0x0F => self.set_interrupt_flag(byte),
|
0x0F => self.set_interrupt_flag(byte),
|
||||||
0x10 => self.apu.ch1.set_sweep(byte),
|
0x10..=0x3F => self.apu.write_byte(addr, byte),
|
||||||
0x11 => self.apu.ch1.set_duty(byte),
|
|
||||||
0x12 => self.apu.ch1.set_envelope(byte),
|
|
||||||
0x13 => self.apu.ch1.set_freq_lo(byte),
|
|
||||||
0x14 => self.apu.ch1.set_freq_hi(byte),
|
|
||||||
0x16 => self.apu.ch2.set_duty(byte),
|
|
||||||
0x17 => self.apu.ch2.set_envelope(byte),
|
|
||||||
0x18 => self.apu.ch2.set_freq_lo(byte),
|
|
||||||
0x19 => self.apu.ch2.set_freq_hi(byte),
|
|
||||||
0x1A => self.apu.ch3.set_enabled(byte),
|
|
||||||
0x1B => self.apu.ch3.set_len(byte),
|
|
||||||
0x1C => self.apu.ch3.set_volume(byte),
|
|
||||||
0x1D => self.apu.ch3.set_freq_lo(byte),
|
|
||||||
0x1E => self.apu.ch3.set_freq_hi(byte),
|
|
||||||
0x20 => self.apu.ch4.set_len(byte),
|
|
||||||
0x21 => self.apu.ch4.set_envelope(byte),
|
|
||||||
0x22 => self.apu.ch4.set_poly(byte),
|
|
||||||
0x23 => self.apu.ch4.set_freq_data(byte),
|
|
||||||
0x24 => self.apu.ctrl.set_channel(byte),
|
|
||||||
0x25 => self.apu.ctrl.set_output(byte),
|
|
||||||
0x26 => self.apu.set_status(byte),
|
|
||||||
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30] = byte,
|
|
||||||
0x40 => self.ppu.ctrl = byte.into(),
|
0x40 => self.ppu.ctrl = byte.into(),
|
||||||
0x41 => self.ppu.stat.update(byte),
|
0x41 => self.ppu.stat.update(byte),
|
||||||
0x42 => self.ppu.pos.scroll_y = byte,
|
0x42 => self.ppu.pos.scroll_y = byte,
|
||||||
|
|
Loading…
Reference in New Issue