diff --git a/Cargo.lock b/Cargo.lock index a4e5291..f9f341f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,6 +61,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + [[package]] name = "bitflags" version = "1.2.1" @@ -465,6 +471,7 @@ name = "gb" version = "0.1.0" dependencies = [ "anyhow", + "bitfield", "pixels", "winit", "winit_input_helper", diff --git a/Cargo.toml b/Cargo.toml index 838fd79..006957a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] anyhow = "^1.0" +bitfield = "0.13.2" pixels = "^0.2" winit = "^0.24" winit_input_helper = "^0.9" diff --git a/src/bus.rs b/src/bus.rs index 61cf715..0ea0011 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -120,9 +120,9 @@ impl Bus { 0xFF0F => self.interrupt.flag.into(), 0xFF11 => self.sound.ch1.sound_duty.into(), 0xFF12 => self.sound.ch1.vol_envelope.into(), - 0xFF14 => self.sound.ch1.freq.get_hi(), + 0xFF14 => self.sound.ch1.freq_hi.into(), 0xFF24 => self.sound.control.channel.into(), - 0xFF25 => self.sound.control.select.into(), + 0xFF25 => self.sound.control.output.into(), 0xFF26 => self.sound.control.status.into(), 0xFF40 => self.ppu.lcd_control.into(), 0xFF41 => self.ppu.stat.into(), @@ -200,10 +200,10 @@ impl Bus { 0xFF0F => self.interrupt.flag = byte.into(), 0xFF11 => self.sound.ch1.sound_duty = byte.into(), 0xFF12 => self.sound.ch1.vol_envelope = byte.into(), - 0xFF13 => self.sound.ch1.freq.set_lo(byte), - 0xFF14 => self.sound.ch1.freq.set_hi(byte), + 0xFF13 => self.sound.ch1.freq_lo = byte.into(), + 0xFF14 => self.sound.ch1.freq_hi = byte.into(), 0xFF24 => self.sound.control.channel = byte.into(), - 0xFF25 => self.sound.control.select = byte.into(), + 0xFF25 => self.sound.control.output = byte.into(), 0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? 0xFF40 => self.ppu.lcd_control = byte.into(), 0xFF41 => self.ppu.stat = byte.into(), diff --git a/src/sound.rs b/src/sound.rs index 03a280d..c7ff620 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -1,5 +1,5 @@ use crate::instruction::Cycles; - +use bitfield::bitfield; #[derive(Debug, Clone, Copy, Default)] pub struct Sound { pub control: SoundControl, @@ -15,16 +15,74 @@ impl Sound { #[derive(Debug, Clone, Copy, Default)] pub struct SoundControl { pub channel: ChannelControl, - pub select: SoundOutputSelect, + pub output: SoundOutput, pub status: SoundStatus, } -#[derive(Debug, Clone, Copy, Default)] -pub struct Frequency { - initial: bool, - freq_type: FrequencyType, - lo: u8, // Bottom 8 bits - hi: u8, // Top 3 bits (11 bits total) +// TODO: What to do about the separation of freq bits +// across multiple registers? +bitfield! { + pub struct FrequencyHigh(u8); + impl Debug; + _, initial: 7; + from into FrequencyType, get_freq_type, set_freq_type: 6; + _, set_freq_high_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 for FrequencyHigh { + fn from(byte: u8) -> Self { + Self(byte) + } +} + +impl From for u8 { + fn from(duty: FrequencyHigh) -> Self { + duty.0 + } +} + +bitfield! { + pub struct FrequencyLow(u8); + impl Debug; + pub _, set_freq_bits: 7, 0; +} + +impl Copy for FrequencyLow {} +impl Clone for FrequencyLow { + fn clone(&self) -> Self { + *self + } +} + +impl Default for FrequencyLow { + fn default() -> Self { + Self(0) + } +} + +impl From for FrequencyLow { + fn from(byte: u8) -> Self { + Self(byte) + } +} + +pub fn get_11bit_freq(low: &FrequencyLow, high: FrequencyHigh) -> u16 { + let high_bits = high.0 & 0b111; + + (low.0 as u16) << 8 | ((high_bits as u16) << 4) } #[derive(Debug, Clone, Copy)] @@ -49,61 +107,38 @@ impl Default for FrequencyType { } } -impl Frequency { - fn get_11bit_freq(&self) -> u16 { - (self.hi as u16) << 8 | self.lo as u16 - } +bitfield! { + pub struct SoundStatus(u8); + impl Debug; + all_enabled, set_all_enabled: 7; + sound_4, _: 3; + sound_3, _: 2; + sound_2, _: 1; + sound_1, _: 0; +} - pub fn set_lo(&mut self, byte: u8) { - self.lo = byte; - } - - pub fn get_lo(&self) -> u8 { - self.lo - } - - pub fn set_hi(&mut self, byte: u8) { - *self = Self { - initial: byte >> 7 == 0x01, - freq_type: ((byte >> 6) & 0x01).into(), - lo: self.lo, - hi: byte & 0x07, - }; - } - - pub fn get_hi(&self) -> u8 { - (self.initial as u8) << 7 | (self.freq_type as u8) << 6 | self.hi +impl Copy for SoundStatus {} +impl Clone for SoundStatus { + fn clone(&self) -> Self { + *self } } -#[derive(Debug, Clone, Copy, Default)] -pub struct SoundStatus { - pub all_enabled: bool, // You can actually write to this one. - sound_4: bool, - sound_3: bool, - sound_2: bool, - sound_1: bool, +impl Default for SoundStatus { + fn default() -> Self { + Self(0) + } } impl From for SoundStatus { fn from(byte: u8) -> Self { - Self { - all_enabled: (byte >> 7) & 0x01 == 0x01, - sound_4: (byte >> 3) & 0x01 == 0x01, - sound_3: (byte >> 2) & 0x01 == 0x01, - sound_2: (byte >> 1) & 0x01 == 0x01, - sound_1: (byte >> 0) & 0x01 == 0x01, - } + Self(byte) } } impl From for u8 { - fn from(status: SoundStatus) -> Self { - (status.all_enabled as u8) << 7 - | (status.sound_4 as u8) << 3 - | (status.sound_3 as u8) << 2 - | (status.sound_2 as u8) << 1 - | (status.sound_1 as u8) << 0 + fn from(duty: SoundStatus) -> Self { + duty.0 } } @@ -111,33 +146,40 @@ impl From for u8 { pub struct Channel1 { pub sound_duty: SoundDuty, pub vol_envelope: VolumeEnvelope, - pub freq: Frequency, + pub freq_hi: FrequencyHigh, + pub freq_lo: FrequencyLow, } -#[derive(Debug, Clone, Copy, Default)] -pub struct VolumeEnvelope { - init_vol: u8, - direction: EnvelopeDirection, - sweep_count: u8, +bitfield! { + pub struct VolumeEnvelope(u8); + impl Debug; + init_vol, set_init_vol: 7, 4; + from into EnvelopeDirection, direction, set_direction: 3; + sweep_count, set_sweep_count: 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 for VolumeEnvelope { fn from(byte: u8) -> Self { - Self { - init_vol: byte >> 4, // Bit 7 -> 4 - direction: ((byte >> 3) & 0x01).into(), // Bit 3 - sweep_count: byte & 0x07, // Bits 2 -> 0 - } + Self(byte) } } impl From for u8 { - fn from(envelope: VolumeEnvelope) -> Self { - let dir_bit: u8 = envelope.direction as u8; - let mut byte = envelope.init_vol << 4; - byte |= dir_bit << 3; - byte |= envelope.sweep_count; - byte + fn from(duty: VolumeEnvelope) -> Self { + duty.0 } } @@ -166,47 +208,66 @@ impl Default for EnvelopeDirection { } } -#[derive(Debug, Clone, Copy, Default)] -pub struct SoundDuty { - wave_pattern: WaveDuty, - sound_length: u8, // +bitfield! { + pub struct SoundDuty(u8); + impl Debug; + from into WavePattern, wave_pattern, set_wave_pattern: 7, 6; + _, set_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 for SoundDuty { fn from(byte: u8) -> Self { - let pattern = byte >> 6; // Get bytes 7 and 6 - let sound_length = byte & 0x3F; // Clear bytes 7 and 6 - - SoundDuty { - wave_pattern: pattern.into(), - sound_length, - } + Self(byte) } } impl From for u8 { fn from(duty: SoundDuty) -> Self { - let mut byte: u8 = duty.wave_pattern as u8; - byte = (byte << 6) | duty.sound_length; - byte + duty.0 + } +} + +impl From for u8 { + fn from(pattern: WavePattern) -> Self { + use WavePattern::*; + + match pattern { + OneEighth => 0b00, + OneQuarter => 0b01, + OneHalf => 0b10, + ThreeQuarters => 0b11, + } } } #[derive(Debug, Clone, Copy)] -pub enum WaveDuty { +pub enum WavePattern { OneEighth = 0, // 12.5% ( _-------_-------_------- ) OneQuarter = 1, // 25% ( __------__------__------ ) OneHalf = 2, // 50% ( ____----____----____---- ) (normal) ThreeQuarters = 3, // 75% ( ______--______--______-- ) } -impl Default for WaveDuty { +impl Default for WavePattern { fn default() -> Self { Self::OneEighth // Rationale: OneEighth is 0x00 } } -impl From for WaveDuty { +impl From for WavePattern { fn from(byte: u8) -> Self { match byte { 0b00 => Self::OneEighth, @@ -218,70 +279,74 @@ impl From for WaveDuty { } } -#[derive(Debug, Clone, Copy, Default)] -pub struct SoundOutputSelect { - pub snd4_term2: bool, - pub snd3_term2: bool, - pub snd2_term2: bool, - pub snd1_term2: bool, - pub snd4_term1: bool, - pub snd3_term1: bool, - pub snd2_term1: bool, - pub snd1_term1: bool, +bitfield! { + pub struct SoundOutput(u8); + impl Debug; + snd4_so2, set_snd4_so2: 7; + snd3_so2, set_snd3_so2: 6; + snd2_so2, set_snd2_so2: 5; + snd1_so2, set_snd1_so2: 4; + snd4_so1, set_snd4_so1: 3; + snd3_so1, set_snd3_so1: 2; + snd2_so1, set_snd2_so1: 1; + snd1_so1, set_snd1_so1: 0; } -impl From for u8 { - fn from(select: SoundOutputSelect) -> Self { - (select.snd4_term2 as u8) << 7 - | (select.snd3_term2 as u8) << 6 - | (select.snd2_term2 as u8) << 5 - | (select.snd1_term2 as u8) << 4 - | (select.snd4_term1 as u8) << 3 - | (select.snd3_term1 as u8) << 2 - | (select.snd2_term1 as u8) << 1 - | (select.snd1_term1 as u8) +impl Copy for SoundOutput {} +impl Clone for SoundOutput { + fn clone(&self) -> Self { + *self } } -impl From for SoundOutputSelect { +impl Default for SoundOutput { + fn default() -> Self { + Self(0) + } +} + +impl From for SoundOutput { fn from(byte: u8) -> Self { - Self { - snd4_term2: byte >> 7 == 0x01, - snd3_term2: (byte >> 6) & 0x01 == 0x01, - snd2_term2: (byte >> 5) & 0x01 == 0x01, - snd1_term2: (byte >> 4) & 0x01 == 0x01, - snd4_term1: (byte >> 3) & 0x01 == 0x01, - snd3_term1: (byte >> 2) & 0x01 == 0x01, - snd2_term1: (byte >> 1) & 0x01 == 0x01, - snd1_term1: byte & 0x01 == 0x01, - } + Self(byte) } } -#[derive(Debug, Clone, Copy, Default)] -pub struct ChannelControl { - vin_to_term2: bool, - term2_level: u8, - vin_to_term1: bool, - term1_level: u8, +impl From for u8 { + fn from(duty: SoundOutput) -> Self { + duty.0 + } +} + +bitfield! { + pub struct ChannelControl(u8); + impl Debug; + vin_so2, set_vin_so2: 7; + so2_level, set_so2_level: 6, 4; + vin_so1, set_vin_so1: 3; + 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 for ChannelControl { fn from(byte: u8) -> Self { - Self { - vin_to_term2: byte >> 7 == 0x01, // Get 7th bit - term2_level: (byte & 0x7F) >> 4, // Clear 7th then get 6 -> 4th bit - vin_to_term1: (byte >> 3) & 0x01 == 0x01, - term1_level: byte & 0x07, // Bits 2 -> 0 - } + Self(byte) } } impl From for u8 { - fn from(control: ChannelControl) -> Self { - (control.vin_to_term1 as u8) << 7 - | (control.term2_level as u8) << 4 - | (control.vin_to_term1 as u8) << 3 - | control.term1_level as u8 + fn from(duty: ChannelControl) -> Self { + duty.0 } }