From 9ddd8ac21c77d655898e45df5bb707087b0fda89 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Tue, 17 Jan 2017 17:56:11 +0100 Subject: [PATCH] Trying to figure this audio stuff out --- src/cartridge.rs | 36 ++- src/cpu.rs | 11 +- src/display.rs | 2 +- src/interconnect.rs | 3 + src/serial.rs | 2 +- src/sound.rs | 612 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 609 insertions(+), 57 deletions(-) diff --git a/src/cartridge.rs b/src/cartridge.rs index 2889082..3fc4793 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -2,7 +2,6 @@ use super::mbc::mbc::MBC; #[derive(Debug,PartialEq)] enum MemoryBankControllerType { - None, MBC1, MBC2, MBC3, @@ -24,11 +23,11 @@ pub struct Cartridge { impl Cartridge { pub fn new(rom: Box<[u8]>, save_file: Option) -> Cartridge { - let mbc_type: MemoryBankControllerType = match rom[0x0147] { - 0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None, - 0x01 ... 0x03 => MemoryBankControllerType::MBC1, - 0x05 ... 0x06 => MemoryBankControllerType::MBC2, - 0x0F ... 0x13 => MemoryBankControllerType::MBC3, + let mbc_type = match rom[0x0147] { + 0x00 | 0x08 ... 0x09 => None, + 0x01 ... 0x03 => Some(MemoryBankControllerType::MBC1), + 0x05 ... 0x06 => Some(MemoryBankControllerType::MBC2), + 0x0F ... 0x13 => Some(MemoryBankControllerType::MBC3), // 0xFF => MemoryBankControllerType::HuC1, _ => panic!("Unsupported MBC type: {:02X}", rom[0x0147]), }; @@ -58,10 +57,10 @@ impl Cartridge { let ram = Cartridge::load_savefile(&save_file, ram_size); let mbc: Box = match mbc_type { - MemoryBankControllerType::None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)), - MemoryBankControllerType::MBC1 => Box::new(super::mbc::mbc1::MBC1::new(rom, ram)), - MemoryBankControllerType::MBC2 => Box::new(super::mbc::mbc2::MBC2::new(rom, ram)), - MemoryBankControllerType::MBC3 => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)), + None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)), + Some(MemoryBankControllerType::MBC1) => Box::new(super::mbc::mbc1::MBC1::new(rom, ram)), + Some(MemoryBankControllerType::MBC2) => Box::new(super::mbc::mbc2::MBC2::new(rom, ram)), + Some(MemoryBankControllerType::MBC3) => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)), }; Cartridge { @@ -71,7 +70,6 @@ impl Cartridge { } fn load_savefile(save_file: &Option, ram_size: RamSize) -> Box<[u8]> { - let old_data; let size = match ram_size { RamSize::None => 0, RamSize::Ram2KB => 2048, @@ -81,22 +79,22 @@ impl Cartridge { if let &Some(ref filename) = save_file { let data = super::read_file(&filename); - if let Ok(success) = data { - old_data = success + if let Ok(data) = data { + data } else { - old_data = vec![0u8; size].into_boxed_slice(); + // Generate empty buffer + println!("Warning: Could not open save file"); + vec![0u8; size].into_boxed_slice() } } else { - old_data = vec![0u8; size].into_boxed_slice(); + vec![0u8; size].into_boxed_slice() } - - old_data } pub fn save(&self) { - if let &Some(ref fil) = &self.savefile { + if let Some(ref fil) = self.savefile { + println!("Updating RAM dump"); self.mbc.dump_ram(fil); - println!("Ram dump updated.") } else { println!("Did not update ram dump"); } diff --git a/src/cpu.rs b/src/cpu.rs index 11db72d..8ff25e1 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -102,7 +102,6 @@ impl CPU { #[inline] fn adc_r(&mut self, val: u8) { - // Passes the test let old: u8 = self.regs[REG_A]; let mut new: u8 = old; let c: u8; @@ -123,7 +122,6 @@ impl CPU { #[inline] fn add_r(&mut self, val: u8) { - // Passes the test let old: u8 = self.regs[REG_A]; let new: u8 = old.wrapping_add(val); let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16); @@ -137,7 +135,6 @@ impl CPU { #[inline] fn sbc_r(&mut self, val: u8) { - // Passes the test let old: u8 = self.regs[REG_A]; let mut new: u8 = old as u8; let c: u8; @@ -159,7 +156,6 @@ impl CPU { #[inline] fn sub_r(&mut self, val: u8) { - // Passes the test let old: u8 = self.regs[REG_A]; let new: u8 = old.wrapping_sub(val); let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16); @@ -173,7 +169,6 @@ impl CPU { #[inline] fn cp_r(&mut self, val: u8) { - // Passes the test let old: u8 = self.regs[REG_A]; let new: u8 = old.wrapping_sub(val); let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16); @@ -866,6 +861,7 @@ impl CPU { pub fn run(&mut self) { loop { + // Some attempt at limiting our speed let mut cycles: i32 = 0; let start = Instant::now(); for _ in 0 .. 1000 { @@ -877,8 +873,6 @@ impl CPU { let delta = gb_dur - our_dur; if delta > (20 * 238) { // We're at least 20 cycles faster. sleep(Duration::new(0, delta as u32)); - } else if delta < 0 { - print!("-"); } } } @@ -889,6 +883,8 @@ impl CPU { let enabled = self.interconnect.read_byte(0xFFFF); let e_pending = pending & enabled; + // Handling interrupts. Do only execute the one with the highest + // priority if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 { if execute { self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK); @@ -1667,7 +1663,6 @@ impl CPU { 16 }, 0xFB => { - // Enable interrupts - TODO if self.debug { println!("EI"); } diff --git a/src/display.rs b/src/display.rs index d3e568c..e33507c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -246,7 +246,7 @@ impl Display { #[inline] pub fn vblank_interrupt(&mut self) -> bool { // Returns whether or not a vblank interrupt should be done - // Yes, this is polling, and yes, this sucks.\ + // Yes, this is polling, and yes, this sucks. if self.vblank_interrupt { self.vblank_interrupt = false; true diff --git a/src/interconnect.rs b/src/interconnect.rs index aee15f7..f717155 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -133,6 +133,9 @@ impl Interconnect { pub fn tick(&mut self, cycles: u8) { self.display.tick(cycles as u16); self.timer.tick(cycles as u16); + for _ in 0..cycles { + self.sound.tick(); + } if self.display.vblank_interrupt() { self.interrupt_request_flags |= INTERRUPT_DISPLAY_VBLANK; diff --git a/src/serial.rs b/src/serial.rs index 59dd0b6..2d07b85 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -12,7 +12,7 @@ impl Serial { pub fn write_byte(&mut self, addr: u16, val: u8) { match addr { 0xFF01 => { - println!("Serial: Write {:02X}", val); + // println!("Serial: Write {:02X}", val); self.data = val; } 0xFF02 => self.control = val, diff --git a/src/sound.rs b/src/sound.rs index 6a6313d..5dbe5d9 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -1,17 +1,501 @@ +const TICK_RATE: usize = 4194304; +const OUTPUT_SAMPLE_RATE: usize = 32768; +const TICKS_PER_SAMPLE: usize = TICK_RATE / OUTPUT_SAMPLE_RATE; + +#[allow(dead_code)] +#[derive(Debug)] +enum EnvelopeDirection { + Increase, + Decrease +} + +#[derive(Debug,Clone)] +struct VolumeEnvelope(u8); +#[allow(dead_code)] +impl VolumeEnvelope { + fn initial_volume(&self) -> u8 { + self.0 >> 4 + } + + fn envelope_direction(&self) -> EnvelopeDirection { + match self.0 & (1 << 3) { + 0 => EnvelopeDirection::Decrease, + _ => EnvelopeDirection::Increase, + } + } + + fn nr_of_envelope_sweep(&self) -> u8 { + self.0 & 0x7 + } + + fn set_nr_of_envelope_sweep(&mut self, nr: u8) { + self.0 &= !0x7; + self.0 |= nr & 0x7; + } +} + +impl From for VolumeEnvelope { + fn from(val: u8) -> VolumeEnvelope { + VolumeEnvelope(val) + } +} + +impl Into for VolumeEnvelope { + fn into(self) -> u8 { + self.0 + } +} + +impl Default for VolumeEnvelope { + fn default() -> VolumeEnvelope { + VolumeEnvelope(0) + } +} + +trait OutputChannel { + fn sample(&mut self) -> i8; + fn clock_length_counter(&mut self); // 256 Hz + fn clock_volume_envelope(&mut self) -> Option; // 64 Hz + + // A square channel's frequency timer period is set to (2048-frequency)*4. + // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through: +} + +#[derive(Debug)] +enum ChannelMode { + CounterMode, + ConsecutiveMode, +} + +impl Default for ChannelMode { + fn default() -> Self { + ChannelMode::CounterMode + } +} + +// Tone & Sweep +#[derive(Debug, Default)] +struct Channel1 { + // MMaped registers + sweep_register: u8, + sound_length: u8, + volume_envelope: VolumeEnvelope, + active_volume_envelope: VolumeEnvelope, + frequency_low: u8, + frequency_high: u8, + + // Registeres used for sound generation + current_phase: f32, + // Depending on sound_length + //sound_enabled: bool, + // Current envelope volume + envelope_volume: u8, + current_mode: ChannelMode, +} + +impl OutputChannel for Channel1 { + /* + According to some specification page: + gb = 2048 - (131072 / Hz) + Hz = 131072 / (2048 - gb) + */ + fn sample(&mut self) -> i8 { + // Right now just assume that we have 100% on time + // I also don't know right now how to disable channel1 :( + let freq = self.current_frequency(); + // sample rate 128? Dunno! + self.current_phase += 1f32 / (2048f32 * TICKS_PER_SAMPLE as f32); + let sample = 2.0 * 3.1415 * freq * self.current_phase; + let volume = (127f32 * self.envelope_volume as f32 / 16f32) as i8; + + if sample.sin() > 0f32 { + volume + } else { + -1 * volume + } + + //(sample.sin() * volume as f32) as i8 + } + + fn clock_length_counter(&mut self) { + if self.frequency_high & (1 << 6) > 0 { + // Use sound length + let sound_length = self.sound_length & 0x3F; + if sound_length > 0 { + self.sound_length &= 0xC0; + self.sound_length |= sound_length - 1; + // self.sound_enabled = true; + } else { + // self.sound_enabled = false; + } + } + } + fn clock_volume_envelope(&mut self) -> Option { + if self.active_volume_envelope.nr_of_envelope_sweep() > 0 { + let left = self.active_volume_envelope.nr_of_envelope_sweep(); + self.active_volume_envelope.set_nr_of_envelope_sweep(left - 1); + match self.active_volume_envelope.envelope_direction() { + EnvelopeDirection::Decrease => { + if self.envelope_volume > 0 { + self.envelope_volume -= 1; + println!("CH1: Decreased envelope volume to {} (steps left: {})", self.envelope_volume, left-1); + } + }, + EnvelopeDirection::Increase => { + if self.envelope_volume < 0xF { + self.envelope_volume += 1; + println!("CH1: Increased envelope volume to {}", self.envelope_volume); + } + } + } + Some(self.active_volume_envelope.envelope_direction()) + } else { + match self.current_mode { + ChannelMode::CounterMode => { + self.envelope_volume = 0; + } + ChannelMode::ConsecutiveMode => { + + } + }; + None + } + } +} + +impl Channel1 { + fn current_frequency(&self) -> f32 { + let full_freq = ((self.frequency_high as u16 & 0x7) << 8) | self.frequency_low as u16; + 131072f32 / (2048f32 - full_freq as f32) + } + + fn write_byte(&mut self, addr: u16, val: u8) { + match addr { + 0xFF10 => { + println!("WARNING: Sound0 sweep not supported yet"); + self.sweep_register = val + }, + 0xFF11 => { + // println!("Channel1: Sound length set to {} (wave pattern: {})", val & 0x3F, val >> 6); + self.sound_length = val; + }, + 0xFF12 => { + self.volume_envelope = val.into(); + }, + 0xFF13 => self.frequency_low = val, + 0xFF14 => { + self.frequency_high = val; + if val & (1 << 7) > 0 { + println!("CH1: started"); + self.active_volume_envelope = self.volume_envelope.clone(); + self.envelope_volume = self.active_volume_envelope.initial_volume(); + } + + self.current_mode = match val & (1 << 6) { + 0 => ChannelMode::CounterMode, + _ => ChannelMode::ConsecutiveMode, + }; + + // self.dump(); + self.frequency_high &= 0x7; + }, + _ => panic!("Invalid addr for channel1 write: {:04X}", addr), + } + } + + pub fn read_byte(&self, addr: u16) -> u8 { + match addr { + 0xFF10 => self.sweep_register, + 0xFF11 => self.sound_length, + 0xFF12 => self.volume_envelope.0, + // 0xFF13 => self.frequency_low, // R/O + 0xFF14 => self.frequency_high & (1 << 6), // Only one bit readable + _ => panic!("Tried to read invalid register {:04X}", addr) + } + } +} + +// Tone +#[derive(Debug, Default)] +struct Channel2 { + sound_length: u8, + volume_envelope: VolumeEnvelope, + active_volume_envelope: VolumeEnvelope, + frequency_low: u8, + frequency_high: u8, + + // Registeres used for sound generation + current_phase: f32, + // Depending on sound_length + // sound_enabled: bool, + // Current envelope volume + envelope_volume: u8, + current_mode: ChannelMode, +} + +impl OutputChannel for Channel2 { + /* + According to some specification page: + gb = 2048 - (131072 / Hz) + Hz = 131072 / (2048 - gb) + */ + fn sample(&mut self) -> i8 { + // Right now just assume that we have 100% on time + // I also don't know right now how to disable channel1 :( + let freq = self.current_frequency(); + // sample rate 128? Dunno! + self.current_phase += 1f32 / (2048f32 * TICKS_PER_SAMPLE as f32); + let sample = 2.0 * 3.1415 * freq * self.current_phase; + // let volume = (127f32 * self.envelope_volume as f32 / 16f32) as i8; + + if sample.sin() > 0f32 { + 40 + } else { + -40 + } + } + + + fn clock_length_counter(&mut self) { + if self.frequency_high & (1 << 6) > 0 { + // Use sound length + let sound_length = self.sound_length & 0x3F; + if sound_length > 0 { + self.sound_length &= 0xC0; + self.sound_length |= sound_length - 1; + } + } + } + fn clock_volume_envelope(&mut self) -> Option { + if self.active_volume_envelope.nr_of_envelope_sweep() > 0 { + let left = self.active_volume_envelope.nr_of_envelope_sweep(); + self.active_volume_envelope.set_nr_of_envelope_sweep(left - 1); + match self.active_volume_envelope.envelope_direction() { + EnvelopeDirection::Decrease => { + if self.envelope_volume > 0 { + self.envelope_volume -= 1; + println!("CH2: Decreased envelope volume to {} (steps left: {})", self.envelope_volume, left-1); + } + }, + EnvelopeDirection::Increase => { + if self.envelope_volume < 0xF { + self.envelope_volume += 1; + println!("CH2: Increased envelope volume to {}", self.envelope_volume); + } + } + } + Some(self.active_volume_envelope.envelope_direction()) + } else { + match self.current_mode { + ChannelMode::CounterMode => { + self.envelope_volume = 0; + } + ChannelMode::ConsecutiveMode => { + + } + }; + None + } + } +} + +impl Channel2 { + fn current_frequency(&self) -> f32 { + let full_freq = ((self.frequency_high as u16 & 0x7) << 8) | self.frequency_low as u16; + 131072f32 / (2048f32 - full_freq as f32) + } + + fn write_byte(&mut self, addr: u16, val: u8) { + match addr { + 0xFF16 => self.sound_length = val, + 0xFF17 => { + self.volume_envelope = val.into(); + }, + 0xFF18 => self.frequency_low = val, + 0xFF19 => { + self.frequency_high = val; + if self.frequency_high & 0x80 == 0x80 { + println!("CH2: Started"); + self.active_volume_envelope = self.volume_envelope.clone(); + self.envelope_volume = self.active_volume_envelope.initial_volume(); + } + + self.current_mode = match val & (1 << 6) { + 0 => ChannelMode::CounterMode, + _ => ChannelMode::ConsecutiveMode, + }; + self.frequency_high &= 0x7; + }, + _ => panic!("Invalid addr for channel2 write: {:04X}", addr), + } + } + + pub fn read_byte(&self, addr: u16) -> u8 { + match addr { + 0xFF16 => self.sound_length, + 0xFF17 => self.volume_envelope.0, + // 0xFF18 => self.frequency_low, // R/O + 0xFF19 => self.frequency_high & (1 << 6), // Only one bit readable + _ => panic!("Tried to read invalid register {:04X}", addr) + } + } +} + +// Wave output +#[derive(Debug, Default)] +struct Channel3 { + enable: u8, + sound_length: u8, + output_level: u8, + frequency_low: u8, + frequency_high: u8, + + wave_pattern_data: [u8; 16], + + // Registeres used for sound generation + ticks_since_enable: usize, + + current_pattern_offset: usize, +} + +impl OutputChannel for Channel3 { + fn sample(&mut self) -> i8 { + if self.enable > 0 { + self.ticks_since_enable += 1; + let val = self.wave_pattern_data[self.current_pattern_offset/2]; + let samp = if val & 1 == 0 { + val >> 4 + } else { + val & 0x0F + }; + + let freq = self.current_frequency(); + if (TICK_RATE as f32 / self.ticks_since_enable as f32) < (freq as f32) { + self.current_pattern_offset += 1; + self.current_pattern_offset %= 32; + self.ticks_since_enable = 0; + } + + let samp = match self.output_level >> 5 { + 0 => 0, + 1 => samp, + 2 => samp >> 1, + _ => samp >> 2, + }; + + let samp = samp << 4; + + samp as i8 + } else { + 0 + } + } + + fn clock_length_counter(&mut self) { + if self.frequency_high & (1 << 6) > 0 { + // Use sound length + let sound_length = self.sound_length & 0x3F; + if sound_length > 0 { + self.sound_length &= 0xC0; + self.sound_length |= sound_length - 1; + // self.sound_enabled = true; + } else { + // self.sound_enabled = false; + self.enable = 0; + } + } + } + fn clock_volume_envelope(&mut self) -> Option { + None + } +} + + +impl Channel3 { + fn current_frequency(&self) -> f32 { + let full_freq = ((self.frequency_high as u16 & 0x7) << 8) | self.frequency_low as u16; + (2048f32 - full_freq as f32) * 2f32 + } + + fn write_byte(&mut self, addr: u16, val: u8) { + match addr { + 0xFF1A => {self.enable = val; self.ticks_since_enable = 0}, + 0xFF1B => self.sound_length = val, + 0xFF1C => self.output_level = val, + 0xFF1D => self.frequency_low = val, + 0xFF1E => { + self.frequency_high = val; + // TODO: Check for start + println!("Starting sound3?"); + self.frequency_high &= 0x7; + }, + 0xFF30...0xFF3F => { + self.wave_pattern_data[addr as usize - 0xFF30] = val; + } + _ => panic!("Invalid addr for channel3 write: {:04X}", addr), + } + } + + pub fn read_byte(&self, addr: u16) -> u8 { + match addr { + 0xFF1A => self.enable, + 0xFF1B => self.sound_length, + 0xFF1C => self.output_level, + //0xFF1D => self.frequency_low, + 0xFF1E => self.frequency_high & 1 << 6, + 0xFF30...0xFF3F => { + self.wave_pattern_data[addr as usize - 0xFF30] + } + _ => panic!("Tried to read invalid register {:04X}", addr) + } + } +} + +// Noise output +#[derive(Debug, Default)] +struct Channel4 { + sound_length: u8, + volume_envelope: VolumeEnvelope, + polynominal_counter: u8, + counter_mode: u8, +} + +impl Channel4 { + fn write_byte(&mut self, addr: u16, val: u8) { + match addr { + 0xFF20 => self.sound_length = val, + 0xFF21 => self.volume_envelope = val.into(), + 0xFF22 => self.polynominal_counter = val, + 0xFF23 => self.counter_mode = val, + _ => panic!("Invalid addr for channel4 write: {:04X}", addr), + } + } + + pub fn read_byte(&self, addr: u16) -> u8 { + match addr { + 0xFF20 => self.sound_length, + 0xFF21 => self.volume_envelope.0, + 0xFF22 => self.polynominal_counter, + 0xFF23 => self.counter_mode, + _ => panic!("Tried to read invalid register {:04X}", addr) + } + } +} + + #[derive(Debug, Default)] pub struct Sound { enabled: u8, - sound_length_1: u8, - sound_control_1: u8, + + channel1: Channel1, + channel2: Channel2, + channel3: Channel3, + channel4: Channel4, + sound_channel_volume_control: u8, sound_output_terminal_selector: u8, - sound_freq_low: u8, - sound_freq_high: u8, - channel2_sound_length: u8, - channel2_volume: u8, - channel2_freq_lo: u8, - channel2_freq_hi: u8, + ticks: usize, } impl Sound { @@ -19,42 +503,114 @@ impl Sound { Sound::default() } - pub fn write_byte(&mut self, addr: u16, val: u8) { - match addr { - 0xFF11 => self.sound_length_1 = val, - 0xFF12 => self.sound_control_1 = val, - 0xFF13 => self.sound_freq_low = val, - 0xFF14 => self.sound_freq_high = val, + pub fn tick(&mut self) { + self.ticks += 1; + // Every 64 Hz volume envelope => all 65536 ticks + // Every 256 Hz length check => all 16384 ticks - 0xFF16 => self.channel2_sound_length = val, - 0xFF17 => self.channel2_volume = val, - 0xFF18 => self.channel2_freq_lo = val, - 0xFF19 => self.channel2_freq_hi = val, + if self.ticks % 65536 == 0 { + self.channel1.clock_volume_envelope(); + self.channel2.clock_volume_envelope(); + } + + if self.ticks % 16384 == 0 { + self.channel1.clock_length_counter(); + self.channel2.clock_length_counter(); + self.channel3.clock_length_counter(); + } + + // How high is our rate? 32768? + if self.ticks % TICKS_PER_SAMPLE == 0 { + // Mix channels. + let mut s01: i16 = 0; + let mut s02: i16 = 0; + + let s01_volume = self.sound_channel_volume_control & 7; + let s02_volume = (self.sound_channel_volume_control >> 4) & 7; + + // Take samples from the channels + let c1_sample = self.channel1.sample(); + let c2_sample = self.channel2.sample(); + // let c3_sample = self.channel3.sample(); + // let c4_sample = self.channel4.sample(); + + //let c1_sample = 0; + //let c2_sample = 0; + let c3_sample = 0; + + // Check S01 + if s01_volume > 0 { + if self.sound_output_terminal_selector & 1 > 0 { + // Output Channel1 + s01 += c1_sample as _; + } + if self.sound_output_terminal_selector & 2 > 0 && false { + // Output Channel2 + s01 += c2_sample as _; + } + if self.sound_output_terminal_selector & 4 > 0 { + // Output Channel3 + s01 += c3_sample as _; + } + if self.sound_output_terminal_selector & 8 > 0 { + // Output Channel4 + } + } + + if s02_volume > 0 { + if self.sound_output_terminal_selector & 0x10 > 0 && false { + // Output Channel1 + s02 += c1_sample as _; + } + if self.sound_output_terminal_selector & 0x20 > 0 { + // Output Channel2 + s02 += c2_sample as _; + } + if self.sound_output_terminal_selector & 0x40 > 0 { + // Output Channel3 + s02 += c3_sample as _; + } + if self.sound_output_terminal_selector & 0x80 > 0 { + // Output Channel4 + } + } + + println!("S:{}:{}", s01 >> 0, s02 >> 0); + } + } + + pub fn write_byte(&mut self, addr: u16, val: u8) { + println!("Snd: {:04X} = {:02X} ({:08b})", addr, val, val); + match addr { + 0xFF10...0xFF14 => self.channel1.write_byte(addr, val), + 0xFF16...0xFF19 => self.channel2.write_byte(addr, val), + 0xFF1A...0xFF1E => self.channel3.write_byte(addr, val), + 0xFF20...0xFF23 => self.channel4.write_byte(addr, val), 0xFF24 => self.sound_channel_volume_control = val, 0xFF25 => self.sound_output_terminal_selector = val, 0xFF26 => self.enabled = val, + 0xFF30...0xFF3F => self.channel3.write_byte(addr, val), + _ => { - // println!("Sound: Write {:02X} to {:04X} unsupported", val, addr); + panic!("Sound: Write {:02X} to {:04X} unsupported", val, addr); }, } } pub fn read_byte(&self, addr: u16) -> u8 { + println!("RD {:04X}", addr); match addr { - 0xFF11 => self.sound_length_1, - 0xFF12 => self.sound_control_1, - 0xFF13 => self.sound_freq_low, - 0xFF14 => self.sound_freq_high, - - 0xFF16 => self.channel2_sound_length, - 0xFF17 => self.channel2_volume, - 0xFF18 => self.channel2_freq_lo, - 0xFF19 => self.channel2_freq_hi, + 0xFF10...0xFF14 => self.channel1.read_byte(addr), + 0xFF16...0xFF19 => self.channel2.read_byte(addr), + 0xFF1A...0xFF1E => self.channel3.read_byte(addr), + 0xFF20...0xFF23 => self.channel4.read_byte(addr), 0xFF24 => self.sound_channel_volume_control, 0xFF25 => self.sound_output_terminal_selector, 0xFF26 => self.enabled, + 0xFF30...0xFF3F => self.channel3.read_byte(addr), + _ => panic!("Sound: Read from {:04X} unsupported", addr), } }