Compare commits
	
		
			2 Commits
		
	
	
		
			08bd33b4d4
			...
			a1eadc0bc4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a1eadc0bc4 | |||
| ea53f97312 | 
@@ -1,10 +1,13 @@
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
 | 
			
		||||
use bitfield::bitfield;
 | 
			
		||||
use crossbeam_channel::{Receiver, Sender, TrySendError};
 | 
			
		||||
use rodio::Source;
 | 
			
		||||
 | 
			
		||||
use crate::emu::SM83_CLOCK_SPEED;
 | 
			
		||||
use gen::{AudioBuffer, AudioSender};
 | 
			
		||||
use types::ch1::{Sweep, SweepDirection};
 | 
			
		||||
use types::ch3::Volume as Ch3Volume;
 | 
			
		||||
use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter};
 | 
			
		||||
use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope};
 | 
			
		||||
use types::{ChannelControl, FrameSequencerState, SoundOutput};
 | 
			
		||||
 | 
			
		||||
pub mod gen;
 | 
			
		||||
mod types;
 | 
			
		||||
 | 
			
		||||
const WAVE_PATTERN_RAM_LEN: usize = 0x10;
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +17,7 @@ const CHANNEL_COUNT: usize = 2;
 | 
			
		||||
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
 | 
			
		||||
 | 
			
		||||
#[derive(Default, Debug, Clone)]
 | 
			
		||||
pub(crate) struct Sound {
 | 
			
		||||
pub(crate) struct Apu {
 | 
			
		||||
    pub(crate) ctrl: SoundControl,
 | 
			
		||||
    /// Tone & Sweep
 | 
			
		||||
    pub(crate) ch1: Channel1,
 | 
			
		||||
@@ -35,7 +38,7 @@ pub(crate) struct Sound {
 | 
			
		||||
    buffer: AudioBuffer<(f32, f32)>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Sound {
 | 
			
		||||
impl Apu {
 | 
			
		||||
    pub(crate) fn clock(&mut self, div: u16) {
 | 
			
		||||
        use FrameSequencerState::*;
 | 
			
		||||
        self.sample_counter += SAMPLE_INCREMENT;
 | 
			
		||||
@@ -136,7 +139,7 @@ impl Sound {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn clock_length_ch4(freq_data: &Channel4Frequency, length_timer: &mut u16, enabled: &mut bool) {
 | 
			
		||||
    fn clock_length_ch4(freq_data: &Ch4Frequency, length_timer: &mut u16, enabled: &mut bool) {
 | 
			
		||||
        if freq_data.idk() && *length_timer > 0 {
 | 
			
		||||
            *length_timer -= 1;
 | 
			
		||||
 | 
			
		||||
@@ -168,7 +171,7 @@ impl Sound {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        Self::clock_length_ch4(
 | 
			
		||||
            &self.ch4.freq_data,
 | 
			
		||||
            &self.ch4.freq,
 | 
			
		||||
            &mut self.ch4.length_timer,
 | 
			
		||||
            &mut self.ch4.enabled,
 | 
			
		||||
        );
 | 
			
		||||
@@ -242,41 +245,6 @@ impl Sound {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
enum FrameSequencerState {
 | 
			
		||||
    Step0Length,
 | 
			
		||||
    Step1Nothing,
 | 
			
		||||
    Step2LengthAndSweep,
 | 
			
		||||
    Step3Nothing,
 | 
			
		||||
    Step4Length,
 | 
			
		||||
    Step5Nothing,
 | 
			
		||||
    Step6LengthAndSweep,
 | 
			
		||||
    Step7VolumeEnvelope,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FrameSequencerState {
 | 
			
		||||
    fn step(&mut self) {
 | 
			
		||||
        use FrameSequencerState::*;
 | 
			
		||||
 | 
			
		||||
        *self = match *self {
 | 
			
		||||
            Step0Length => Step1Nothing,
 | 
			
		||||
            Step1Nothing => Step2LengthAndSweep,
 | 
			
		||||
            Step2LengthAndSweep => Step3Nothing,
 | 
			
		||||
            Step3Nothing => Step4Length,
 | 
			
		||||
            Step4Length => Step5Nothing,
 | 
			
		||||
            Step5Nothing => Step6LengthAndSweep,
 | 
			
		||||
            Step6LengthAndSweep => Step7VolumeEnvelope,
 | 
			
		||||
            Step7VolumeEnvelope => Step0Length,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for FrameSequencerState {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self::Step0Length
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, Default)]
 | 
			
		||||
pub(crate) struct SoundControl {
 | 
			
		||||
    /// 0xFF24 | NR50 - Channel Control
 | 
			
		||||
@@ -289,7 +257,7 @@ pub(crate) struct SoundControl {
 | 
			
		||||
 | 
			
		||||
impl SoundControl {
 | 
			
		||||
    /// 0xFF26 | NR52 - Sound On/Off
 | 
			
		||||
    pub fn status(&self, snd: &Sound) -> u8 {
 | 
			
		||||
    pub(crate) fn status(&self, snd: &Apu) -> u8 {
 | 
			
		||||
        (self.enabled as u8) << 7
 | 
			
		||||
            | (snd.ch4.enabled as u8) << 3
 | 
			
		||||
            | (snd.ch3.enabled as u8) << 2
 | 
			
		||||
@@ -298,82 +266,12 @@ impl SoundControl {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 0xFF26 | NR52 - Sound On/Off
 | 
			
		||||
    pub fn set_status(&mut self, byte: u8) {
 | 
			
		||||
    pub(crate) fn set_status(&mut self, byte: u8) {
 | 
			
		||||
        // TODO: Should all channel enabled fields be disabled when this is reset?
 | 
			
		||||
        self.enabled = (byte >> 7) & 0x01 == 0x01;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: What to do about the separation of freq bits
 | 
			
		||||
// across multiple registers?
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct FrequencyHigh(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    initial, set_initial: 7;
 | 
			
		||||
    idk, set_idk: 6; // TODO: Figure out what the hell this is
 | 
			
		||||
    freq_bits, set_freq_bits: 2, 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for FrequencyHigh {}
 | 
			
		||||
impl Clone for FrequencyHigh {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for FrequencyHigh {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for FrequencyHigh {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<FrequencyHigh> for u8 {
 | 
			
		||||
    fn from(freq: FrequencyHigh) -> Self {
 | 
			
		||||
        freq.0 & 0x40 // Only bit 6 can be read
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct SoundStatus(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    pub all_enabled, set_all_enabled: 7;
 | 
			
		||||
    pub sound_4, _: 3;
 | 
			
		||||
    pub sound_3, _: 2;
 | 
			
		||||
    pub sound_2, _: 1;
 | 
			
		||||
    pub sound_1, _: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for SoundStatus {}
 | 
			
		||||
impl Clone for SoundStatus {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for SoundStatus {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for SoundStatus {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SoundStatus> for u8 {
 | 
			
		||||
    fn from(status: SoundStatus) -> Self {
 | 
			
		||||
        status.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, Default)]
 | 
			
		||||
pub(crate) struct Channel1 {
 | 
			
		||||
    /// 0xFF10 | NR10 - Channel 1 Sweep Register
 | 
			
		||||
@@ -507,61 +405,6 @@ impl Channel1 {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct Sweep(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    period, set_period: 6, 4;
 | 
			
		||||
    from into SweepDirection, direction, set_direction: 3, 3;
 | 
			
		||||
    shift_count, set_shift_count: 2, 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for Sweep {}
 | 
			
		||||
impl Clone for Sweep {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Sweep {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for Sweep {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Sweep> for u8 {
 | 
			
		||||
    fn from(sweep: Sweep) -> Self {
 | 
			
		||||
        sweep.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
enum SweepDirection {
 | 
			
		||||
    Increase = 0,
 | 
			
		||||
    Decrease = 1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for SweepDirection {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        match byte & 0x01 {
 | 
			
		||||
            0b00 => Self::Increase,
 | 
			
		||||
            0b01 => Self::Decrease,
 | 
			
		||||
            _ => unreachable!("{:04X} is not a valid value for SweepChange", byte),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SweepDirection> for u8 {
 | 
			
		||||
    fn from(change: SweepDirection) -> Self {
 | 
			
		||||
        change as u8
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, Default)]
 | 
			
		||||
pub(crate) struct Channel2 {
 | 
			
		||||
    /// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
 | 
			
		||||
@@ -647,145 +490,6 @@ impl Channel2 {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct VolumeEnvelope(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    pub init_vol, set_init_vol: 7, 4;
 | 
			
		||||
    pub from into EnvelopeDirection, direction, set_direction: 3, 3;
 | 
			
		||||
    pub period, set_period: 2, 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for VolumeEnvelope {}
 | 
			
		||||
impl Clone for VolumeEnvelope {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for VolumeEnvelope {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for VolumeEnvelope {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<VolumeEnvelope> for u8 {
 | 
			
		||||
    fn from(envelope: VolumeEnvelope) -> Self {
 | 
			
		||||
        envelope.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub enum EnvelopeDirection {
 | 
			
		||||
    Decrease = 0,
 | 
			
		||||
    Increase = 1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for EnvelopeDirection {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        match byte & 0b01 {
 | 
			
		||||
            0b00 => Self::Decrease,
 | 
			
		||||
            0b01 => Self::Increase,
 | 
			
		||||
            _ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<EnvelopeDirection> for u8 {
 | 
			
		||||
    fn from(direction: EnvelopeDirection) -> Self {
 | 
			
		||||
        direction as u8
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for EnvelopeDirection {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self::Decrease
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
   pub struct SoundDuty(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
   pub from into WavePattern, wave_pattern, set_wave_pattern: 7, 6;
 | 
			
		||||
   pub sound_length, _: 5, 0; // TODO: Getter only used if bit 6 in NR14 is set
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for SoundDuty {}
 | 
			
		||||
impl Clone for SoundDuty {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for SoundDuty {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for SoundDuty {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SoundDuty> for u8 {
 | 
			
		||||
    fn from(duty: SoundDuty) -> Self {
 | 
			
		||||
        duty.0 & 0xC0 // Only bits 7 and 6 can be read
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub enum WavePattern {
 | 
			
		||||
    OneEighth = 0,     // 12.5% ( _-------_-------_------- )
 | 
			
		||||
    OneQuarter = 1,    // 25%   ( __------__------__------ )
 | 
			
		||||
    OneHalf = 2,       // 50%   ( ____----____----____---- ) (normal)
 | 
			
		||||
    ThreeQuarters = 3, // 75%   ( ______--______--______-- )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl WavePattern {
 | 
			
		||||
    pub const fn amplitude(&self, index: u8) -> u8 {
 | 
			
		||||
        use WavePattern::*;
 | 
			
		||||
        let i = 7 - index; // an index of 0 should get the highest bit
 | 
			
		||||
 | 
			
		||||
        match *self {
 | 
			
		||||
            OneEighth => (0b00000001 >> i) & 0x01,
 | 
			
		||||
            OneQuarter => (0b10000001 >> i) & 0x01,
 | 
			
		||||
            OneHalf => (0b10000111 >> i) & 0x01,
 | 
			
		||||
            ThreeQuarters => (0b01111110 >> i) & 0x01,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for WavePattern {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self::OneEighth // Rationale: OneEighth is 0x00
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<WavePattern> for u8 {
 | 
			
		||||
    fn from(pattern: WavePattern) -> Self {
 | 
			
		||||
        pattern as Self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for WavePattern {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        match byte & 0b11 {
 | 
			
		||||
            0b00 => Self::OneEighth,
 | 
			
		||||
            0b01 => Self::OneQuarter,
 | 
			
		||||
            0b10 => Self::OneHalf,
 | 
			
		||||
            0b11 => Self::ThreeQuarters,
 | 
			
		||||
            _ => unreachable!("{:#04X} is not a valid value for WavePattern", byte),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, Default)]
 | 
			
		||||
pub(crate) struct Channel3 {
 | 
			
		||||
    /// 0xFF1A | NR30 - Channel 3 Sound on/off
 | 
			
		||||
@@ -793,7 +497,7 @@ pub(crate) struct Channel3 {
 | 
			
		||||
    /// 0xFF1B | NR31 - Sound Length
 | 
			
		||||
    len: u8,
 | 
			
		||||
    /// 0xFF1C | NR32 - Channel 3 Volume
 | 
			
		||||
    volume: Channel3Volume,
 | 
			
		||||
    volume: Ch3Volume,
 | 
			
		||||
    /// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
 | 
			
		||||
    freq_lo: u8,
 | 
			
		||||
    /// 0xFF1E | NR34 - Channel 3 Frequency high
 | 
			
		||||
@@ -854,7 +558,7 @@ impl Channel3 {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn set_volume(&mut self, byte: u8) {
 | 
			
		||||
        use Channel3Volume::*;
 | 
			
		||||
        use Ch3Volume::*;
 | 
			
		||||
 | 
			
		||||
        self.volume = match (byte >> 5) & 0x03 {
 | 
			
		||||
            0b00 => Mute,
 | 
			
		||||
@@ -899,33 +603,6 @@ impl Channel3 {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
enum Channel3Volume {
 | 
			
		||||
    Mute = 0,
 | 
			
		||||
    Full = 1,
 | 
			
		||||
    Half = 2,
 | 
			
		||||
    Quarter = 3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Channel3Volume {
 | 
			
		||||
    pub fn shift_count(&self) -> u8 {
 | 
			
		||||
        use Channel3Volume::*;
 | 
			
		||||
 | 
			
		||||
        match *self {
 | 
			
		||||
            Mute => 4,
 | 
			
		||||
            Full => 0,
 | 
			
		||||
            Half => 1,
 | 
			
		||||
            Quarter => 2,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Channel3Volume {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self::Mute
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, Default)]
 | 
			
		||||
pub(crate) struct Channel4 {
 | 
			
		||||
    /// 0xFF20 | NR41 - Channel 4 Sound Length
 | 
			
		||||
@@ -935,7 +612,7 @@ pub(crate) struct Channel4 {
 | 
			
		||||
    /// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
 | 
			
		||||
    pub(crate) poly: PolynomialCounter,
 | 
			
		||||
    /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
 | 
			
		||||
    freq_data: Channel4Frequency,
 | 
			
		||||
    freq: Ch4Frequency,
 | 
			
		||||
 | 
			
		||||
    // Envelope Functionality
 | 
			
		||||
    period_timer: u8,
 | 
			
		||||
@@ -966,14 +643,14 @@ impl Channel4 {
 | 
			
		||||
 | 
			
		||||
    /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
 | 
			
		||||
    pub(crate) fn freq_data(&self) -> u8 {
 | 
			
		||||
        u8::from(self.freq_data) & 0x40 // only bit 6 readable
 | 
			
		||||
        u8::from(self.freq) & 0x40 // only bit 6 readable
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
 | 
			
		||||
    pub(crate) fn set_freq_data(&mut self, byte: u8) {
 | 
			
		||||
        self.freq_data = byte.into();
 | 
			
		||||
        self.freq = byte.into();
 | 
			
		||||
 | 
			
		||||
        if self.freq_data.initial() {
 | 
			
		||||
        if self.freq.initial() {
 | 
			
		||||
            // Envelope behaviour during trigger event
 | 
			
		||||
            self.period_timer = self.envelope.period();
 | 
			
		||||
            self.current_volume = self.envelope.init_vol();
 | 
			
		||||
@@ -1020,250 +697,3 @@ impl Channel4 {
 | 
			
		||||
        code << 4
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct PolynomialCounter(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    shift_count, set_shift_count: 7, 4;
 | 
			
		||||
    from into CounterWidth, counter_width, set_counter_width: 3, 3;
 | 
			
		||||
    divisor_code, set_divisor_code: 2, 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for PolynomialCounter {}
 | 
			
		||||
impl Clone for PolynomialCounter {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for PolynomialCounter {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for PolynomialCounter {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PolynomialCounter> for u8 {
 | 
			
		||||
    fn from(poly: PolynomialCounter) -> Self {
 | 
			
		||||
        poly.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
enum CounterWidth {
 | 
			
		||||
    Long,  // 15 bits long
 | 
			
		||||
    Short, // 7 bits long
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for CounterWidth {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        match byte & 0x01 {
 | 
			
		||||
            0b00 => Self::Short,
 | 
			
		||||
            0b01 => Self::Long,
 | 
			
		||||
            _ => unreachable!("{:#04X} is not a valid value for CounterWidth"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<CounterWidth> for u8 {
 | 
			
		||||
    fn from(counter_width: CounterWidth) -> Self {
 | 
			
		||||
        counter_width as u8
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct Channel4Frequency(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    initial, set_initial: 7;
 | 
			
		||||
    idk, set_idk: 6; // TODO: same as FrequencyHigh, figure out what this is
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for Channel4Frequency {}
 | 
			
		||||
impl Clone for Channel4Frequency {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Channel4Frequency {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for Channel4Frequency {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte & 0xC0) // Only bits 7 and 6 hold anything of value
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Channel4Frequency> for u8 {
 | 
			
		||||
    fn from(state: Channel4Frequency) -> Self {
 | 
			
		||||
        state.0 & 0x40 // Only bit 6 holds anything of value
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct SoundOutput(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    pub ch4_left, set_ch4_left: 7;
 | 
			
		||||
    pub ch3_left, set_ch3_left: 6;
 | 
			
		||||
    pub ch2_left, set_ch2_left: 5;
 | 
			
		||||
    pub ch1_left, set_ch1_left: 4;
 | 
			
		||||
    pub ch4_right, set_ch4_right: 3;
 | 
			
		||||
    pub ch3_right, set_ch3_right: 2;
 | 
			
		||||
    pub ch2_right, set_ch2_right: 1;
 | 
			
		||||
    pub ch1_right, set_ch1_right: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for SoundOutput {}
 | 
			
		||||
impl Clone for SoundOutput {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for SoundOutput {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for SoundOutput {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SoundOutput> for u8 {
 | 
			
		||||
    fn from(output: SoundOutput) -> Self {
 | 
			
		||||
        output.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct ChannelControl(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    pub vin_so2, set_vin_so2: 7;
 | 
			
		||||
    pub so2_level, set_so2_level: 6, 4;
 | 
			
		||||
    pub vin_so1, set_vin_so1: 3;
 | 
			
		||||
    pub so1_level, set_so1_level: 2, 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for ChannelControl {}
 | 
			
		||||
impl Clone for ChannelControl {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for ChannelControl {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for ChannelControl {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ChannelControl> for u8 {
 | 
			
		||||
    fn from(ctrl: ChannelControl) -> Self {
 | 
			
		||||
        ctrl.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AudioMPSC;
 | 
			
		||||
 | 
			
		||||
impl AudioMPSC {
 | 
			
		||||
    pub fn new() -> (AudioSender<f32>, AudioReceiver<f32>) {
 | 
			
		||||
        // TODO: Can we provide an upper limit for this?
 | 
			
		||||
        // The larger this channel is, the more lag there is between the Audio and
 | 
			
		||||
        // Emulator
 | 
			
		||||
        let (send, recv) = crossbeam_channel::unbounded();
 | 
			
		||||
 | 
			
		||||
        (AudioSender { inner: send }, AudioReceiver { inner: recv })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct AudioSender<T> {
 | 
			
		||||
    inner: Sender<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> AudioSender<T> {
 | 
			
		||||
    fn send_samples(&self, left: T, right: T) -> Result<(), TrySendError<T>> {
 | 
			
		||||
        self.inner.try_send(left).and(self.inner.try_send(right))?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AudioReceiver<T> {
 | 
			
		||||
    inner: Receiver<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> Iterator for AudioReceiver<T> {
 | 
			
		||||
    type Item = T;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        // TODO: Should this never return none?
 | 
			
		||||
        self.inner.recv().ok()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: rodio::Sample> Source for AudioReceiver<T> {
 | 
			
		||||
    fn current_frame_len(&self) -> Option<usize> {
 | 
			
		||||
        // A frame changes when the samples rate or
 | 
			
		||||
        // number of channels change. This will never happen, so
 | 
			
		||||
        // we return
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn channels(&self) -> u16 {
 | 
			
		||||
        // The Gameboy supports two channels
 | 
			
		||||
        CHANNEL_COUNT as u16
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn sample_rate(&self) -> u32 {
 | 
			
		||||
        SAMPLE_RATE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn total_duration(&self) -> Option<std::time::Duration> {
 | 
			
		||||
        // The duration of this source is infinite
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct AudioBuffer<T> {
 | 
			
		||||
    inner: VecDeque<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> Default for AudioBuffer<T> {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            inner: VecDeque::with_capacity(AUDIO_BUFFER_LEN * CHANNEL_COUNT),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> AudioBuffer<T> {
 | 
			
		||||
    pub fn push_back(&mut self, value: T) {
 | 
			
		||||
        self.inner.push_back(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn pop_front(&mut self) -> Option<T> {
 | 
			
		||||
        self.inner.pop_front()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn len(&self) -> usize {
 | 
			
		||||
        self.inner.len()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								src/apu/gen.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/apu/gen.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
use super::{AUDIO_BUFFER_LEN, CHANNEL_COUNT, SAMPLE_RATE};
 | 
			
		||||
use crossbeam_channel::{Receiver, Sender, TrySendError};
 | 
			
		||||
use rodio::Source;
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
 | 
			
		||||
pub struct AudioMPSC;
 | 
			
		||||
 | 
			
		||||
impl AudioMPSC {
 | 
			
		||||
    pub fn new() -> (AudioSender<f32>, AudioReceiver<f32>) {
 | 
			
		||||
        // TODO: Can we provide an upper limit for this?
 | 
			
		||||
        // The larger this channel is, the more lag there is between the Audio and
 | 
			
		||||
        // Emulator
 | 
			
		||||
        let (send, recv) = crossbeam_channel::unbounded();
 | 
			
		||||
 | 
			
		||||
        (AudioSender { inner: send }, AudioReceiver { inner: recv })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct AudioSender<T> {
 | 
			
		||||
    inner: Sender<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> AudioSender<T> {
 | 
			
		||||
    pub(crate) fn send_samples(&self, left: T, right: T) -> Result<(), TrySendError<T>> {
 | 
			
		||||
        self.inner.try_send(left).and(self.inner.try_send(right))?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AudioReceiver<T> {
 | 
			
		||||
    inner: Receiver<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> Iterator for AudioReceiver<T> {
 | 
			
		||||
    type Item = T;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        // TODO: Should this never return none?
 | 
			
		||||
        self.inner.recv().ok()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: rodio::Sample> Source for AudioReceiver<T> {
 | 
			
		||||
    fn current_frame_len(&self) -> Option<usize> {
 | 
			
		||||
        // A frame changes when the samples rate or
 | 
			
		||||
        // number of channels change. This will never happen, so
 | 
			
		||||
        // we return
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn channels(&self) -> u16 {
 | 
			
		||||
        // The Gameboy supports two channels
 | 
			
		||||
        CHANNEL_COUNT as u16
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn sample_rate(&self) -> u32 {
 | 
			
		||||
        SAMPLE_RATE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn total_duration(&self) -> Option<std::time::Duration> {
 | 
			
		||||
        // The duration of this source is infinite
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub(crate) struct AudioBuffer<T> {
 | 
			
		||||
    inner: VecDeque<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> Default for AudioBuffer<T> {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            inner: VecDeque::with_capacity(AUDIO_BUFFER_LEN * CHANNEL_COUNT),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> AudioBuffer<T> {
 | 
			
		||||
    pub(crate) fn push_back(&mut self, value: T) {
 | 
			
		||||
        self.inner.push_back(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn pop_front(&mut self) -> Option<T> {
 | 
			
		||||
        self.inner.pop_front()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn len(&self) -> usize {
 | 
			
		||||
        self.inner.len()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										535
									
								
								src/apu/types.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								src/apu/types.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,535 @@
 | 
			
		||||
use bitfield::bitfield;
 | 
			
		||||
 | 
			
		||||
pub(crate) mod ch1 {
 | 
			
		||||
    use super::bitfield;
 | 
			
		||||
 | 
			
		||||
    bitfield! {
 | 
			
		||||
        pub struct Sweep(u8);
 | 
			
		||||
        impl Debug;
 | 
			
		||||
        _period, _: 6, 4;
 | 
			
		||||
        from into SweepDirection, _direction, _: 3, 3;
 | 
			
		||||
        _shift_count, _: 2, 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Sweep {
 | 
			
		||||
        pub(crate) fn period(&self) -> u8 {
 | 
			
		||||
            self._period()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn shift_count(&self) -> u8 {
 | 
			
		||||
            self._shift_count()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn direction(&self) -> SweepDirection {
 | 
			
		||||
            self._direction()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Copy for Sweep {}
 | 
			
		||||
    impl Clone for Sweep {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            *self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for Sweep {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self(0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for Sweep {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            Self(byte)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<Sweep> for u8 {
 | 
			
		||||
        fn from(sweep: Sweep) -> Self {
 | 
			
		||||
            sweep.0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Debug, Clone, Copy)]
 | 
			
		||||
    pub(crate) enum SweepDirection {
 | 
			
		||||
        Increase = 0,
 | 
			
		||||
        Decrease = 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for SweepDirection {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            match byte & 0x01 {
 | 
			
		||||
                0b00 => Self::Increase,
 | 
			
		||||
                0b01 => Self::Decrease,
 | 
			
		||||
                _ => unreachable!("{:04X} is not a valid value for SweepChange", byte),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<SweepDirection> for u8 {
 | 
			
		||||
        fn from(change: SweepDirection) -> Self {
 | 
			
		||||
            change as u8
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) mod ch3 {
 | 
			
		||||
    #[derive(Debug, Clone, Copy)]
 | 
			
		||||
    pub(crate) enum Volume {
 | 
			
		||||
        Mute = 0,
 | 
			
		||||
        Full = 1,
 | 
			
		||||
        Half = 2,
 | 
			
		||||
        Quarter = 3,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Volume {
 | 
			
		||||
        pub(crate) fn shift_count(&self) -> u8 {
 | 
			
		||||
            use Volume::*;
 | 
			
		||||
 | 
			
		||||
            match *self {
 | 
			
		||||
                Mute => 4,
 | 
			
		||||
                Full => 0,
 | 
			
		||||
                Half => 1,
 | 
			
		||||
                Quarter => 2,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for Volume {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self::Mute
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) mod ch4 {
 | 
			
		||||
    use super::bitfield;
 | 
			
		||||
 | 
			
		||||
    bitfield! {
 | 
			
		||||
        pub struct PolynomialCounter(u8);
 | 
			
		||||
        impl Debug;
 | 
			
		||||
        _shift_count, _: 7, 4;
 | 
			
		||||
        from into CounterWidth, _counter_width, _: 3, 3;
 | 
			
		||||
        _divisor_code, _: 2, 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl PolynomialCounter {
 | 
			
		||||
        pub(crate) fn divisor_code(&self) -> u8 {
 | 
			
		||||
            self._divisor_code()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn counter_width(&self) -> CounterWidth {
 | 
			
		||||
            self._counter_width()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn shift_count(&self) -> u8 {
 | 
			
		||||
            self._shift_count()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Copy for PolynomialCounter {}
 | 
			
		||||
    impl Clone for PolynomialCounter {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            *self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for PolynomialCounter {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self(0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for PolynomialCounter {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            Self(byte)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<PolynomialCounter> for u8 {
 | 
			
		||||
        fn from(poly: PolynomialCounter) -> Self {
 | 
			
		||||
            poly.0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Debug, Clone, Copy)]
 | 
			
		||||
    pub(crate) enum CounterWidth {
 | 
			
		||||
        Long,  // 15 bits long
 | 
			
		||||
        Short, // 7 bits long
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for CounterWidth {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            match byte & 0x01 {
 | 
			
		||||
                0b00 => Self::Short,
 | 
			
		||||
                0b01 => Self::Long,
 | 
			
		||||
                _ => unreachable!("{:#04X} is not a valid value for CounterWidth"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<CounterWidth> for u8 {
 | 
			
		||||
        fn from(counter_width: CounterWidth) -> Self {
 | 
			
		||||
            counter_width as u8
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bitfield! {
 | 
			
		||||
        pub struct Frequency(u8);
 | 
			
		||||
        impl Debug;
 | 
			
		||||
        _initial, _: 7;
 | 
			
		||||
        _idk, _: 6; // TODO: same as FrequencyHigh, figure out what this is
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Frequency {
 | 
			
		||||
        pub(crate) fn idk(&self) -> bool {
 | 
			
		||||
            self._idk()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn initial(&self) -> bool {
 | 
			
		||||
            self._initial()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Copy for Frequency {}
 | 
			
		||||
    impl Clone for Frequency {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            *self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for Frequency {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self(0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for Frequency {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            Self(byte & 0xC0) // Only bits 7 and 6 hold anything of value
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<Frequency> for u8 {
 | 
			
		||||
        fn from(state: Frequency) -> Self {
 | 
			
		||||
            state.0 & 0x40 // Only bit 6 holds anything of value
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) mod common {
 | 
			
		||||
    use super::bitfield;
 | 
			
		||||
 | 
			
		||||
    bitfield! {
 | 
			
		||||
        pub struct FrequencyHigh(u8);
 | 
			
		||||
        impl Debug;
 | 
			
		||||
        _initial, _: 7;
 | 
			
		||||
        _idk, _: 6; // TODO: Figure out what the hell this is
 | 
			
		||||
        pub freq_bits, set_freq_bits: 2, 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl FrequencyHigh {
 | 
			
		||||
        pub(crate) fn initial(&self) -> bool {
 | 
			
		||||
            self._initial()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn idk(&self) -> bool {
 | 
			
		||||
            self._idk()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Copy for FrequencyHigh {}
 | 
			
		||||
    impl Clone for FrequencyHigh {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            *self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for FrequencyHigh {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self(0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for FrequencyHigh {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            Self(byte)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<FrequencyHigh> for u8 {
 | 
			
		||||
        fn from(freq: FrequencyHigh) -> Self {
 | 
			
		||||
            freq.0 & 0x40 // Only bit 6 can be read
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bitfield! {
 | 
			
		||||
        pub struct VolumeEnvelope(u8);
 | 
			
		||||
        impl Debug;
 | 
			
		||||
        _init_vol, _: 7, 4;
 | 
			
		||||
        from into EnvelopeDirection, _direction, _: 3, 3;
 | 
			
		||||
        _period, _: 2, 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl VolumeEnvelope {
 | 
			
		||||
        pub(crate) fn init_vol(&self) -> u8 {
 | 
			
		||||
            self._init_vol()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn direction(&self) -> EnvelopeDirection {
 | 
			
		||||
            self._direction()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn period(&self) -> u8 {
 | 
			
		||||
            self._period()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Copy for VolumeEnvelope {}
 | 
			
		||||
    impl Clone for VolumeEnvelope {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            *self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for VolumeEnvelope {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self(0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for VolumeEnvelope {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            Self(byte)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<VolumeEnvelope> for u8 {
 | 
			
		||||
        fn from(envelope: VolumeEnvelope) -> Self {
 | 
			
		||||
            envelope.0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Debug, Clone, Copy)]
 | 
			
		||||
    pub(crate) enum EnvelopeDirection {
 | 
			
		||||
        Decrease = 0,
 | 
			
		||||
        Increase = 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for EnvelopeDirection {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            match byte & 0b01 {
 | 
			
		||||
                0b00 => Self::Decrease,
 | 
			
		||||
                0b01 => Self::Increase,
 | 
			
		||||
                _ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<EnvelopeDirection> for u8 {
 | 
			
		||||
        fn from(direction: EnvelopeDirection) -> Self {
 | 
			
		||||
            direction as u8
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for EnvelopeDirection {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self::Decrease
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bitfield! {
 | 
			
		||||
        pub struct SoundDuty(u8);
 | 
			
		||||
        impl Debug;
 | 
			
		||||
        from into WavePattern, _wave_pattern, _: 7, 6;
 | 
			
		||||
        _sound_length, _: 5, 0; // TODO: Getter only used if bit 6 in NR14 is set
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl SoundDuty {
 | 
			
		||||
        pub(crate) fn wave_pattern(&self) -> WavePattern {
 | 
			
		||||
            self._wave_pattern()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub(crate) fn sound_length(&self) -> u8 {
 | 
			
		||||
            self._sound_length()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Copy for SoundDuty {}
 | 
			
		||||
    impl Clone for SoundDuty {
 | 
			
		||||
        fn clone(&self) -> Self {
 | 
			
		||||
            *self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for SoundDuty {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self(0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for SoundDuty {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            Self(byte)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<SoundDuty> for u8 {
 | 
			
		||||
        fn from(duty: SoundDuty) -> Self {
 | 
			
		||||
            duty.0 & 0xC0 // Only bits 7 and 6 can be read
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Debug, Clone, Copy)]
 | 
			
		||||
    pub(crate) enum WavePattern {
 | 
			
		||||
        OneEighth = 0,     // 12.5% ( _-------_-------_------- )
 | 
			
		||||
        OneQuarter = 1,    // 25%   ( __------__------__------ )
 | 
			
		||||
        OneHalf = 2,       // 50%   ( ____----____----____---- ) (normal)
 | 
			
		||||
        ThreeQuarters = 3, // 75%   ( ______--______--______-- )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl WavePattern {
 | 
			
		||||
        pub(crate) const fn amplitude(&self, index: u8) -> u8 {
 | 
			
		||||
            use WavePattern::*;
 | 
			
		||||
            let i = 7 - index; // an index of 0 should get the highest bit
 | 
			
		||||
 | 
			
		||||
            match *self {
 | 
			
		||||
                OneEighth => (0b00000001 >> i) & 0x01,
 | 
			
		||||
                OneQuarter => (0b10000001 >> i) & 0x01,
 | 
			
		||||
                OneHalf => (0b10000111 >> i) & 0x01,
 | 
			
		||||
                ThreeQuarters => (0b01111110 >> i) & 0x01,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for WavePattern {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self::OneEighth // Rationale: OneEighth is 0x00
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<WavePattern> for u8 {
 | 
			
		||||
        fn from(pattern: WavePattern) -> Self {
 | 
			
		||||
            pattern as Self
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<u8> for WavePattern {
 | 
			
		||||
        fn from(byte: u8) -> Self {
 | 
			
		||||
            match byte & 0b11 {
 | 
			
		||||
                0b00 => Self::OneEighth,
 | 
			
		||||
                0b01 => Self::OneQuarter,
 | 
			
		||||
                0b10 => Self::OneHalf,
 | 
			
		||||
                0b11 => Self::ThreeQuarters,
 | 
			
		||||
                _ => unreachable!("{:#04X} is not a valid value for WavePattern", byte),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub(crate) enum FrameSequencerState {
 | 
			
		||||
    Step0Length,
 | 
			
		||||
    Step1Nothing,
 | 
			
		||||
    Step2LengthAndSweep,
 | 
			
		||||
    Step3Nothing,
 | 
			
		||||
    Step4Length,
 | 
			
		||||
    Step5Nothing,
 | 
			
		||||
    Step6LengthAndSweep,
 | 
			
		||||
    Step7VolumeEnvelope,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FrameSequencerState {
 | 
			
		||||
    pub(crate) fn step(&mut self) {
 | 
			
		||||
        use FrameSequencerState::*;
 | 
			
		||||
 | 
			
		||||
        *self = match *self {
 | 
			
		||||
            Step0Length => Step1Nothing,
 | 
			
		||||
            Step1Nothing => Step2LengthAndSweep,
 | 
			
		||||
            Step2LengthAndSweep => Step3Nothing,
 | 
			
		||||
            Step3Nothing => Step4Length,
 | 
			
		||||
            Step4Length => Step5Nothing,
 | 
			
		||||
            Step5Nothing => Step6LengthAndSweep,
 | 
			
		||||
            Step6LengthAndSweep => Step7VolumeEnvelope,
 | 
			
		||||
            Step7VolumeEnvelope => Step0Length,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for FrameSequencerState {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self::Step0Length
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct SoundOutput(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    pub ch4_left, _: 7;
 | 
			
		||||
    pub ch3_left, _: 6;
 | 
			
		||||
    pub ch2_left, _: 5;
 | 
			
		||||
    pub ch1_left, _: 4;
 | 
			
		||||
    pub ch4_right, _: 3;
 | 
			
		||||
    pub ch3_right, _: 2;
 | 
			
		||||
    pub ch2_right, _: 1;
 | 
			
		||||
    pub ch1_right, _: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for SoundOutput {}
 | 
			
		||||
impl Clone for SoundOutput {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for SoundOutput {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for SoundOutput {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SoundOutput> for u8 {
 | 
			
		||||
    fn from(output: SoundOutput) -> Self {
 | 
			
		||||
        output.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bitfield! {
 | 
			
		||||
    pub struct ChannelControl(u8);
 | 
			
		||||
    impl Debug;
 | 
			
		||||
    vin_so2, _: 7;
 | 
			
		||||
    so2_level, _: 6, 4;
 | 
			
		||||
    vin_so1, _: 3;
 | 
			
		||||
    so1_level, _: 2, 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Copy for ChannelControl {}
 | 
			
		||||
impl Clone for ChannelControl {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for ChannelControl {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<u8> for ChannelControl {
 | 
			
		||||
    fn from(byte: u8) -> Self {
 | 
			
		||||
        Self(byte)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ChannelControl> for u8 {
 | 
			
		||||
    fn from(ctrl: ChannelControl) -> Self {
 | 
			
		||||
        ctrl.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								src/bus.rs
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								src/bus.rs
									
									
									
									
									
								
							@@ -1,10 +1,11 @@
 | 
			
		||||
use crate::apu::gen::AudioSender;
 | 
			
		||||
use crate::apu::Apu;
 | 
			
		||||
use crate::cartridge::Cartridge;
 | 
			
		||||
use crate::high_ram::HighRam;
 | 
			
		||||
use crate::interrupt::{Interrupt, InterruptFlag};
 | 
			
		||||
use crate::joypad::Joypad;
 | 
			
		||||
use crate::ppu::{Ppu, PpuMode};
 | 
			
		||||
use crate::serial::Serial;
 | 
			
		||||
use crate::sound::{AudioSender, Sound};
 | 
			
		||||
use crate::timer::Timer;
 | 
			
		||||
use crate::work_ram::{VariableWorkRam, WorkRam};
 | 
			
		||||
use std::{fs::File, io::Read};
 | 
			
		||||
@@ -20,7 +21,7 @@ pub struct Bus {
 | 
			
		||||
    var_ram: VariableWorkRam,
 | 
			
		||||
    pub(crate) timer: Timer,
 | 
			
		||||
    int: Interrupt,
 | 
			
		||||
    snd: Sound,
 | 
			
		||||
    apu: Apu,
 | 
			
		||||
    high_ram: HighRam,
 | 
			
		||||
    serial: Serial,
 | 
			
		||||
    pub(crate) joypad: Joypad,
 | 
			
		||||
@@ -36,7 +37,7 @@ impl Default for Bus {
 | 
			
		||||
            var_ram: Default::default(),
 | 
			
		||||
            timer: Default::default(),
 | 
			
		||||
            int: Default::default(),
 | 
			
		||||
            snd: Default::default(),
 | 
			
		||||
            apu: Default::default(),
 | 
			
		||||
            high_ram: Default::default(),
 | 
			
		||||
            serial: Default::default(),
 | 
			
		||||
            joypad: Default::default(),
 | 
			
		||||
@@ -66,22 +67,22 @@ impl Bus {
 | 
			
		||||
        self.cartridge.as_ref()?.title()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn apu(&self) -> &Apu {
 | 
			
		||||
        &self.apu
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn apu_mut(&mut self) -> &mut Apu {
 | 
			
		||||
        &mut self.apu
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn pass_audio_src(&mut self, sender: AudioSender<f32>) {
 | 
			
		||||
        self.snd.set_audio_src(sender)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn is_full(&self) -> bool {
 | 
			
		||||
        self.snd.is_full()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn flush_samples(&mut self) {
 | 
			
		||||
        self.snd.flush_samples()
 | 
			
		||||
        self.apu.set_audio_src(sender)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn clock(&mut self) {
 | 
			
		||||
        self.ppu.clock();
 | 
			
		||||
        self.timer.clock();
 | 
			
		||||
        self.snd.clock(self.timer.divider);
 | 
			
		||||
        self.apu.clock(self.timer.divider);
 | 
			
		||||
        self.clock_dma();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -228,25 +229,25 @@ impl BusIo for Bus {
 | 
			
		||||
                    0x06 => self.timer.modulo,
 | 
			
		||||
                    0x07 => self.timer.ctrl.into(),
 | 
			
		||||
                    0x0F => self.interrupt_flag().into(),
 | 
			
		||||
                    0x10 => self.snd.ch1.sweep.into(),
 | 
			
		||||
                    0x11 => self.snd.ch1.duty(),
 | 
			
		||||
                    0x12 => self.snd.ch1.envelope.into(),
 | 
			
		||||
                    0x14 => self.snd.ch1.freq_hi(),
 | 
			
		||||
                    0x16 => self.snd.ch2.duty(),
 | 
			
		||||
                    0x17 => self.snd.ch2.envelope.into(),
 | 
			
		||||
                    0x19 => self.snd.ch2.freq_hi(),
 | 
			
		||||
                    0x1A => self.snd.ch3.enabled(),
 | 
			
		||||
                    0x1B => self.snd.ch3.len(),
 | 
			
		||||
                    0x1C => self.snd.ch3.volume(),
 | 
			
		||||
                    0x1E => self.snd.ch3.freq_hi(),
 | 
			
		||||
                    0x20 => self.snd.ch4.len(),
 | 
			
		||||
                    0x21 => self.snd.ch4.envelope.into(),
 | 
			
		||||
                    0x22 => self.snd.ch4.poly.into(),
 | 
			
		||||
                    0x23 => self.snd.ch4.freq_data(),
 | 
			
		||||
                    0x24 => self.snd.ctrl.channel.into(),
 | 
			
		||||
                    0x25 => self.snd.ctrl.output.into(),
 | 
			
		||||
                    0x26 => self.snd.ctrl.status(&self.snd),
 | 
			
		||||
                    0x30..=0x3F => self.snd.ch3.wave_ram[addr as usize - 0xFF30],
 | 
			
		||||
                    0x10 => self.apu.ch1.sweep.into(),
 | 
			
		||||
                    0x11 => self.apu.ch1.duty(),
 | 
			
		||||
                    0x12 => self.apu.ch1.envelope.into(),
 | 
			
		||||
                    0x14 => self.apu.ch1.freq_hi(),
 | 
			
		||||
                    0x16 => self.apu.ch2.duty(),
 | 
			
		||||
                    0x17 => self.apu.ch2.envelope.into(),
 | 
			
		||||
                    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.into(),
 | 
			
		||||
                    0x22 => self.apu.ch4.poly.into(),
 | 
			
		||||
                    0x23 => self.apu.ch4.freq_data(),
 | 
			
		||||
                    0x24 => self.apu.ctrl.channel.into(),
 | 
			
		||||
                    0x25 => self.apu.ctrl.output.into(),
 | 
			
		||||
                    0x26 => self.apu.ctrl.status(&self.apu),
 | 
			
		||||
                    0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30],
 | 
			
		||||
                    0x40 => self.ppu.ctrl.into(),
 | 
			
		||||
                    0x41 => self.ppu.stat.into(),
 | 
			
		||||
                    0x42 => self.ppu.pos.scroll_y,
 | 
			
		||||
@@ -343,28 +344,28 @@ impl BusIo for Bus {
 | 
			
		||||
                    0x06 => self.timer.modulo = byte,
 | 
			
		||||
                    0x07 => self.timer.ctrl = byte.into(),
 | 
			
		||||
                    0x0F => self.set_interrupt_flag(byte),
 | 
			
		||||
                    0x10 => self.snd.ch1.sweep = byte.into(),
 | 
			
		||||
                    0x11 => self.snd.ch1.set_duty(byte),
 | 
			
		||||
                    0x12 => self.snd.ch1.envelope = byte.into(),
 | 
			
		||||
                    0x13 => self.snd.ch1.set_freq_lo(byte),
 | 
			
		||||
                    0x14 => self.snd.ch1.set_freq_hi(byte),
 | 
			
		||||
                    0x16 => self.snd.ch2.set_duty(byte),
 | 
			
		||||
                    0x17 => self.snd.ch2.envelope = byte.into(),
 | 
			
		||||
                    0x18 => self.snd.ch2.set_freq_lo(byte),
 | 
			
		||||
                    0x19 => self.snd.ch2.set_freq_hi(byte),
 | 
			
		||||
                    0x1A => self.snd.ch3.set_enabled(byte),
 | 
			
		||||
                    0x1B => self.snd.ch3.set_len(byte),
 | 
			
		||||
                    0x1C => self.snd.ch3.set_volume(byte),
 | 
			
		||||
                    0x1D => self.snd.ch3.set_freq_lo(byte),
 | 
			
		||||
                    0x1E => self.snd.ch3.set_freq_hi(byte),
 | 
			
		||||
                    0x20 => self.snd.ch4.set_len(byte),
 | 
			
		||||
                    0x21 => self.snd.ch4.envelope = byte.into(),
 | 
			
		||||
                    0x22 => self.snd.ch4.poly = byte.into(),
 | 
			
		||||
                    0x23 => self.snd.ch4.set_freq_data(byte),
 | 
			
		||||
                    0x24 => self.snd.ctrl.channel = byte.into(),
 | 
			
		||||
                    0x25 => self.snd.ctrl.output = byte.into(),
 | 
			
		||||
                    0x26 => self.snd.ctrl.set_status(byte), // FIXME: Should we control which bytes are written to here?
 | 
			
		||||
                    0x30..=0x3F => self.snd.ch3.wave_ram[addr as usize - 0xFF30] = byte,
 | 
			
		||||
                    0x10 => self.apu.ch1.sweep = byte.into(),
 | 
			
		||||
                    0x11 => self.apu.ch1.set_duty(byte),
 | 
			
		||||
                    0x12 => self.apu.ch1.envelope = byte.into(),
 | 
			
		||||
                    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.envelope = byte.into(),
 | 
			
		||||
                    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.envelope = byte.into(),
 | 
			
		||||
                    0x22 => self.apu.ch4.poly = byte.into(),
 | 
			
		||||
                    0x23 => self.apu.ch4.set_freq_data(byte),
 | 
			
		||||
                    0x24 => self.apu.ctrl.channel = byte.into(),
 | 
			
		||||
                    0x25 => self.apu.ctrl.output = byte.into(),
 | 
			
		||||
                    0x26 => self.apu.ctrl.set_status(byte), // FIXME: Should we control which bytes are written to here?
 | 
			
		||||
                    0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30] = byte,
 | 
			
		||||
                    0x40 => self.ppu.ctrl = byte.into(),
 | 
			
		||||
                    0x41 => self.ppu.stat.update(byte),
 | 
			
		||||
                    0x42 => self.ppu.pos.scroll_y = byte,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
use crate::apu::gen::AudioSender;
 | 
			
		||||
use crate::bus::{Bus, BusIo};
 | 
			
		||||
use crate::instruction::{Cycle, Instruction};
 | 
			
		||||
use crate::interrupt::{InterruptEnable, InterruptFlag};
 | 
			
		||||
use crate::joypad::Joypad;
 | 
			
		||||
use crate::ppu::Ppu;
 | 
			
		||||
use crate::sound::AudioSender;
 | 
			
		||||
use crate::timer::Timer;
 | 
			
		||||
use bitfield::bitfield;
 | 
			
		||||
use std::fmt::{Display, Formatter, Result as FmtResult};
 | 
			
		||||
@@ -128,11 +128,11 @@ impl Cpu {
 | 
			
		||||
        let mut elapsed = 0x00;
 | 
			
		||||
        let pending: u32 = cycles.into();
 | 
			
		||||
        while elapsed < pending {
 | 
			
		||||
            if !self.bus.is_full() {
 | 
			
		||||
            if !self.bus.apu().is_full() {
 | 
			
		||||
                self.bus.clock();
 | 
			
		||||
                elapsed += 1;
 | 
			
		||||
            } else {
 | 
			
		||||
                self.bus.flush_samples();
 | 
			
		||||
                self.bus.apu_mut().flush_samples();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
pub use apu::gen::AudioMPSC;
 | 
			
		||||
pub use gui::Egui;
 | 
			
		||||
pub use instruction::Cycle;
 | 
			
		||||
pub use sound::AudioMPSC;
 | 
			
		||||
 | 
			
		||||
pub const GB_WIDTH: usize = 160;
 | 
			
		||||
pub const GB_HEIGHT: usize = 144;
 | 
			
		||||
 | 
			
		||||
mod apu;
 | 
			
		||||
mod bus;
 | 
			
		||||
mod cartridge;
 | 
			
		||||
mod cpu;
 | 
			
		||||
@@ -16,6 +17,5 @@ mod interrupt;
 | 
			
		||||
mod joypad;
 | 
			
		||||
mod ppu;
 | 
			
		||||
mod serial;
 | 
			
		||||
mod sound;
 | 
			
		||||
mod timer;
 | 
			
		||||
mod work_ram;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user