Compare commits
4 Commits
3fb182b9cb
...
9e36e86c14
Author | SHA1 | Date |
---|---|---|
Rekai Nyangadzayi Musuka | 9e36e86c14 | |
Rekai Nyangadzayi Musuka | 6f6c308d84 | |
Rekai Nyangadzayi Musuka | f429d72882 | |
Rekai Nyangadzayi Musuka | 4fda7587ce |
247
src/apu.rs
247
src/apu.rs
|
@ -127,6 +127,49 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 0xFF26 | NR52 - Sound On/Off
|
||||||
|
pub(crate) fn set_status(&mut self, byte: u8) {
|
||||||
|
self.ctrl.enabled = (byte >> 7) & 0x01 == 0x01;
|
||||||
|
|
||||||
|
if !self.ctrl.enabled {
|
||||||
|
self.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ch1.enabled = self.ctrl.enabled;
|
||||||
|
self.ch2.enabled = self.ctrl.enabled;
|
||||||
|
self.ch3.enabled = self.ctrl.enabled;
|
||||||
|
self.ch4.enabled = self.ctrl.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
// TODO: Clear readable sound registers
|
||||||
|
|
||||||
|
self.ch1.sweep = Default::default();
|
||||||
|
self.ch1.duty = Default::default();
|
||||||
|
self.ch1.envelope = Default::default();
|
||||||
|
self.ch1.freq_hi = Default::default(); // FIXME: What about frequency low?
|
||||||
|
|
||||||
|
self.ch2.duty = Default::default();
|
||||||
|
self.ch2.envelope = Default::default();
|
||||||
|
self.ch2.freq_hi = Default::default();
|
||||||
|
|
||||||
|
self.ch3.enabled = Default::default();
|
||||||
|
self.ch3.len = Default::default();
|
||||||
|
self.ch3.volume = Default::default();
|
||||||
|
self.ch3.freq_hi = Default::default();
|
||||||
|
|
||||||
|
self.ch4.len = Default::default();
|
||||||
|
self.ch4.envelope = Default::default();
|
||||||
|
self.ch4.poly = Default::default();
|
||||||
|
self.ch4.freq = Default::default();
|
||||||
|
|
||||||
|
self.ch2 = Default::default();
|
||||||
|
self.ch3 = Default::default();
|
||||||
|
self.ch4 = Default::default();
|
||||||
|
self.ctrl.channel = Default::default();
|
||||||
|
self.ctrl.output = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
|
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
|
||||||
if freq_hi.idk() && *length_timer > 0 {
|
if freq_hi.idk() && *length_timer > 0 {
|
||||||
*length_timer -= 1;
|
*length_timer -= 1;
|
||||||
|
@ -248,38 +291,56 @@ impl Apu {
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct SoundControl {
|
pub(crate) struct SoundControl {
|
||||||
/// 0xFF24 | NR50 - Channel Control
|
/// 0xFF24 | NR50 - Channel Control
|
||||||
pub(crate) channel: ChannelControl,
|
channel: ChannelControl,
|
||||||
/// 0xFF25 | NR51 - Selection of Sound output terminal
|
/// 0xFF25 | NR51 - Selection of Sound output terminal
|
||||||
pub(crate) output: SoundOutput,
|
output: SoundOutput,
|
||||||
|
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SoundControl {
|
impl SoundControl {
|
||||||
/// 0xFF26 | NR52 - Sound On/Off
|
/// 0xFF24 | NR50 - Channel Control
|
||||||
pub(crate) fn status(&self, snd: &Apu) -> u8 {
|
pub(crate) fn channel(&self) -> u8 {
|
||||||
(self.enabled as u8) << 7
|
u8::from(self.channel)
|
||||||
| (snd.ch4.enabled as u8) << 3
|
}
|
||||||
| (snd.ch3.enabled as u8) << 2
|
|
||||||
| (snd.ch2.enabled as u8) << 1
|
/// 0xFF24 | NR50 - Channel Control
|
||||||
| snd.ch1.enabled as u8
|
pub(crate) fn set_channel(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.channel = byte.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF25 | NR51 - Selection of Sound output terminal
|
||||||
|
pub(crate) fn output(&self) -> u8 {
|
||||||
|
u8::from(self.output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF25 | NR51 - Selection of Sound output terminal
|
||||||
|
pub(crate) fn set_output(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.output = byte.into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF26 | NR52 - Sound On/Off
|
/// 0xFF26 | NR52 - Sound On/Off
|
||||||
pub(crate) fn set_status(&mut self, byte: u8) {
|
pub(crate) fn status(&self, apu: &Apu) -> u8 {
|
||||||
// TODO: Should all channel enabled fields be disabled when this is reset?
|
(self.enabled as u8) << 7
|
||||||
self.enabled = (byte >> 7) & 0x01 == 0x01;
|
| (apu.ch4.enabled as u8) << 3
|
||||||
|
| (apu.ch3.enabled as u8) << 2
|
||||||
|
| (apu.ch2.enabled as u8) << 1
|
||||||
|
| apu.ch1.enabled as u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct Channel1 {
|
pub(crate) struct Channel1 {
|
||||||
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
||||||
pub(crate) sweep: Sweep,
|
sweep: Sweep,
|
||||||
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
|
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
|
||||||
duty: SoundDuty,
|
duty: SoundDuty,
|
||||||
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
|
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
|
||||||
pub(crate) envelope: VolumeEnvelope,
|
envelope: VolumeEnvelope,
|
||||||
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
|
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
|
||||||
freq_lo: u8,
|
freq_lo: u8,
|
||||||
/// 0xFF14 | NR14 - Channel 1 Frequency high
|
/// 0xFF14 | NR14 - Channel 1 Frequency high
|
||||||
|
@ -322,29 +383,58 @@ impl Channel1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
||||||
|
pub(crate) fn sweep(&self) -> u8 {
|
||||||
|
u8::from(self.sweep) | 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
||||||
|
pub(crate) fn set_sweep(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.sweep = byte.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
|
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
|
||||||
pub(crate) fn duty(&self) -> u8 {
|
pub(crate) fn duty(&self) -> u8 {
|
||||||
u8::from(self.duty) & 0xC0 // Only bits 7 and 6 can be read
|
u8::from(self.duty) | 0x3F
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
|
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
|
||||||
pub(crate) fn set_duty(&mut self, byte: u8) {
|
pub(crate) fn set_duty(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.duty = byte.into();
|
self.duty = byte.into();
|
||||||
self.length_timer = 64 - self.duty.sound_length() as u16;
|
self.length_timer = 64 - self.duty.sound_length() as u16;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
|
||||||
|
pub fn envelope(&self) -> u8 {
|
||||||
|
u8::from(self.envelope)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
|
||||||
|
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.envelope = byte.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
|
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
|
||||||
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
|
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq_lo = byte;
|
self.freq_lo = byte;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF14 | NR14 - Channel 1 Frequency high
|
/// 0xFF14 | NR14 - Channel 1 Frequency high
|
||||||
pub(crate) fn freq_hi(&self) -> u8 {
|
pub(crate) fn freq_hi(&self) -> u8 {
|
||||||
u8::from(self.freq_hi) & 0x40 // Only bit 6 is readable
|
u8::from(self.freq_hi) | 0xBF
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF14 | NR14 - Channel 1 Frequency high
|
/// 0xFF14 | NR14 - Channel 1 Frequency high
|
||||||
pub(crate) fn set_freq_hi(&mut self, byte: u8) {
|
pub(crate) fn set_freq_hi(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq_hi = byte.into();
|
self.freq_hi = byte.into();
|
||||||
|
|
||||||
// If this bit is set, a trigger event occurs
|
// If this bit is set, a trigger event occurs
|
||||||
|
@ -375,6 +465,7 @@ impl Channel1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn calc_sweep_freq(&mut self) -> u16 {
|
fn calc_sweep_freq(&mut self) -> u16 {
|
||||||
use SweepDirection::*;
|
use SweepDirection::*;
|
||||||
|
@ -410,7 +501,7 @@ pub(crate) struct Channel2 {
|
||||||
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
||||||
duty: SoundDuty,
|
duty: SoundDuty,
|
||||||
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
|
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
|
||||||
pub(crate) envelope: VolumeEnvelope,
|
envelope: VolumeEnvelope,
|
||||||
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
|
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
|
||||||
freq_lo: u8,
|
freq_lo: u8,
|
||||||
/// 0xFF19 | NR24 - Channel 2 Frequency high
|
/// 0xFF19 | NR24 - Channel 2 Frequency high
|
||||||
|
@ -450,27 +541,44 @@ impl Channel2 {
|
||||||
|
|
||||||
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
||||||
pub(crate) fn duty(&self) -> u8 {
|
pub(crate) fn duty(&self) -> u8 {
|
||||||
u8::from(self.duty) & 0xC0 // Only bits 7 & 6 are readable
|
u8::from(self.duty) | 0x3F
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
||||||
pub(crate) fn set_duty(&mut self, byte: u8) {
|
pub(crate) fn set_duty(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.duty = byte.into();
|
self.duty = byte.into();
|
||||||
self.length_timer = 64 - self.duty.sound_length() as u16;
|
self.length_timer = 64 - self.duty.sound_length() as u16;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
|
||||||
|
pub(crate) fn envelope(&self) -> u8 {
|
||||||
|
u8::from(self.envelope)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
|
||||||
|
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.envelope = byte.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
|
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
|
||||||
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
|
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq_lo = byte;
|
self.freq_lo = byte;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF19 | NR24 - Channel 2 Frequency high
|
/// 0xFF19 | NR24 - Channel 2 Frequency high
|
||||||
pub(crate) fn freq_hi(&self) -> u8 {
|
pub(crate) fn freq_hi(&self) -> u8 {
|
||||||
u8::from(self.freq_hi) & 0x40 // only bit 6 is readable
|
u8::from(self.freq_hi) | 0xBF
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF19 | NR24 - Channel 2 Frequency high
|
/// 0xFF19 | NR24 - Channel 2 Frequency high
|
||||||
pub(crate) fn set_freq_hi(&mut self, byte: u8) {
|
pub(crate) fn set_freq_hi(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq_hi = byte.into();
|
self.freq_hi = byte.into();
|
||||||
|
|
||||||
if self.freq_hi.initial() {
|
if self.freq_hi.initial() {
|
||||||
|
@ -484,6 +592,7 @@ impl Channel2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn frequency(&self) -> u16 {
|
fn frequency(&self) -> u16 {
|
||||||
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
|
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
|
||||||
|
@ -512,29 +621,64 @@ pub(crate) struct Channel3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel3 {
|
impl Channel3 {
|
||||||
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
|
pub(crate) fn enabled(&self) -> u8 {
|
||||||
|
((self.enabled as u8) << 7) | 0x7F
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
|
pub(crate) fn set_enabled(&mut self, byte: u8) {
|
||||||
|
self.enabled = (byte >> 7) & 0x01 == 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF1B | NR31 - Sound Length
|
/// 0xFF1B | NR31 - Sound Length
|
||||||
pub(crate) fn len(&self) -> u8 {
|
pub(crate) fn len(&self) -> u8 {
|
||||||
self.len
|
self.len | 0xFF
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF1B | NR31 - Sound Length
|
/// 0xFF1B | NR31 - Sound Length
|
||||||
pub(crate) fn set_len(&mut self, byte: u8) {
|
pub(crate) fn set_len(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.len = byte;
|
self.len = byte;
|
||||||
self.length_timer = 256 - self.len as u16;
|
self.length_timer = 256 - self.len as u16;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF1C | NR32 - Channel 3 Volume
|
||||||
|
pub(crate) fn volume(&self) -> u8 {
|
||||||
|
((self.volume as u8) << 5) | 0x9F
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF1C | NR32 - Channel 3 Volume
|
||||||
|
pub(crate) fn set_volume(&mut self, byte: u8) {
|
||||||
|
use Ch3Volume::*;
|
||||||
|
|
||||||
|
if self.enabled {
|
||||||
|
self.volume = match (byte >> 5) & 0x03 {
|
||||||
|
0b00 => Mute,
|
||||||
|
0b01 => Full,
|
||||||
|
0b10 => Half,
|
||||||
|
0b11 => Quarter,
|
||||||
|
_ => unreachable!("{:#04X} is not a valid value for Channel3Volume", byte),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
|
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
|
||||||
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
|
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq_lo = byte;
|
self.freq_lo = byte;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
||||||
pub(crate) fn freq_hi(&self) -> u8 {
|
pub(crate) fn freq_hi(&self) -> u8 {
|
||||||
u8::from(self.freq_hi) & 0x40 // Only bit 6 readable
|
u8::from(self.freq_hi) | 0xBF
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
||||||
pub(crate) fn set_freq_hi(&mut self, byte: u8) {
|
pub(crate) fn set_freq_hi(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq_hi = byte.into();
|
self.freq_hi = byte.into();
|
||||||
|
|
||||||
if self.freq_hi.initial() {
|
if self.freq_hi.initial() {
|
||||||
|
@ -544,29 +688,6 @@ impl Channel3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enabled(&self) -> u8 {
|
|
||||||
(self.enabled as u8) << 7
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_enabled(&mut self, byte: u8) {
|
|
||||||
self.enabled = (byte >> 7) & 0x01 == 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn volume(&self) -> u8 {
|
|
||||||
(self.volume as u8) << 5
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_volume(&mut self, byte: u8) {
|
|
||||||
use Ch3Volume::*;
|
|
||||||
|
|
||||||
self.volume = match (byte >> 5) & 0x03 {
|
|
||||||
0b00 => Mute,
|
|
||||||
0b01 => Full,
|
|
||||||
0b10 => Half,
|
|
||||||
0b11 => Quarter,
|
|
||||||
_ => unreachable!("{:#04X} is not a valid value for Channel3Volume", byte),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn amplitude(&self) -> f32 {
|
fn amplitude(&self) -> f32 {
|
||||||
|
@ -608,9 +729,9 @@ pub(crate) struct Channel4 {
|
||||||
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
||||||
len: u8,
|
len: u8,
|
||||||
/// 0xFF21 | NR42 - Channel 4 Volume Envelope
|
/// 0xFF21 | NR42 - Channel 4 Volume Envelope
|
||||||
pub(crate) envelope: VolumeEnvelope,
|
envelope: VolumeEnvelope,
|
||||||
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
||||||
pub(crate) poly: PolynomialCounter,
|
poly: PolynomialCounter,
|
||||||
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
||||||
freq: Ch4Frequency,
|
freq: Ch4Frequency,
|
||||||
|
|
||||||
|
@ -632,22 +753,49 @@ pub(crate) struct Channel4 {
|
||||||
impl Channel4 {
|
impl Channel4 {
|
||||||
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
||||||
pub(crate) fn len(&self) -> u8 {
|
pub(crate) fn len(&self) -> u8 {
|
||||||
self.len & 0x3F
|
self.len | 0xFF
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
||||||
pub(crate) fn set_len(&mut self, byte: u8) {
|
pub(crate) fn set_len(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.len = byte & 0x3F;
|
self.len = byte & 0x3F;
|
||||||
self.length_timer = 256 - self.len as u16;
|
self.length_timer = 256 - self.len as u16;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF21 | NR42 - Channel 4 Volume Envelope
|
||||||
|
pub(crate) fn envelope(&self) -> u8 {
|
||||||
|
u8::from(self.envelope)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF21 | NR42 - Channel 4 Volume Envelope
|
||||||
|
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.envelope = byte.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
||||||
|
pub(crate) fn poly(&self) -> u8 {
|
||||||
|
u8::from(self.poly)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
||||||
|
pub(crate) fn set_poly(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
|
self.poly = byte.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
||||||
pub(crate) fn freq_data(&self) -> u8 {
|
pub(crate) fn frequency(&self) -> u8 {
|
||||||
u8::from(self.freq) & 0x40 // only bit 6 readable
|
u8::from(self.freq) | 0xBF
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
||||||
pub(crate) fn set_freq_data(&mut self, byte: u8) {
|
pub(crate) fn set_freq_data(&mut self, byte: u8) {
|
||||||
|
if self.enabled {
|
||||||
self.freq = byte.into();
|
self.freq = byte.into();
|
||||||
|
|
||||||
if self.freq.initial() {
|
if self.freq.initial() {
|
||||||
|
@ -664,6 +812,7 @@ impl Channel4 {
|
||||||
self.lf_shift = 0x7FFF;
|
self.lf_shift = 0x7FFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn amplitude(&self) -> f32 {
|
fn amplitude(&self) -> f32 {
|
||||||
let dac_input = (!self.lf_shift & 0x01) as u8 * self.current_volume;
|
let dac_input = (!self.lf_shift & 0x01) as u8 * self.current_volume;
|
||||||
|
|
40
src/bus.rs
40
src/bus.rs
|
@ -224,23 +224,23 @@ impl BusIo for Bus {
|
||||||
0x06 => self.timer.modulo,
|
0x06 => self.timer.modulo,
|
||||||
0x07 => self.timer.ctrl.into(),
|
0x07 => self.timer.ctrl.into(),
|
||||||
0x0F => self.interrupt_flag().into(),
|
0x0F => self.interrupt_flag().into(),
|
||||||
0x10 => self.apu.ch1.sweep.into(),
|
0x10 => self.apu.ch1.sweep(),
|
||||||
0x11 => self.apu.ch1.duty(),
|
0x11 => self.apu.ch1.duty(),
|
||||||
0x12 => self.apu.ch1.envelope.into(),
|
0x12 => self.apu.ch1.envelope(),
|
||||||
0x14 => self.apu.ch1.freq_hi(),
|
0x14 => self.apu.ch1.freq_hi(),
|
||||||
0x16 => self.apu.ch2.duty(),
|
0x16 => self.apu.ch2.duty(),
|
||||||
0x17 => self.apu.ch2.envelope.into(),
|
0x17 => self.apu.ch2.envelope(),
|
||||||
0x19 => self.apu.ch2.freq_hi(),
|
0x19 => self.apu.ch2.freq_hi(),
|
||||||
0x1A => self.apu.ch3.enabled(),
|
0x1A => self.apu.ch3.enabled(),
|
||||||
0x1B => self.apu.ch3.len(),
|
0x1B => self.apu.ch3.len(),
|
||||||
0x1C => self.apu.ch3.volume(),
|
0x1C => self.apu.ch3.volume(),
|
||||||
0x1E => self.apu.ch3.freq_hi(),
|
0x1E => self.apu.ch3.freq_hi(),
|
||||||
0x20 => self.apu.ch4.len(),
|
0x20 => self.apu.ch4.len(),
|
||||||
0x21 => self.apu.ch4.envelope.into(),
|
0x21 => self.apu.ch4.envelope(),
|
||||||
0x22 => self.apu.ch4.poly.into(),
|
0x22 => self.apu.ch4.poly(),
|
||||||
0x23 => self.apu.ch4.freq_data(),
|
0x23 => self.apu.ch4.frequency(),
|
||||||
0x24 => self.apu.ctrl.channel.into(),
|
0x24 => self.apu.ctrl.channel(),
|
||||||
0x25 => self.apu.ctrl.output.into(),
|
0x25 => self.apu.ctrl.output(),
|
||||||
0x26 => self.apu.ctrl.status(&self.apu),
|
0x26 => self.apu.ctrl.status(&self.apu),
|
||||||
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30],
|
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30],
|
||||||
0x40 => self.ppu.ctrl.into(),
|
0x40 => self.ppu.ctrl.into(),
|
||||||
|
@ -256,7 +256,10 @@ impl BusIo for Bus {
|
||||||
0x4A => self.ppu.pos.window_y,
|
0x4A => self.ppu.pos.window_y,
|
||||||
0x4B => self.ppu.pos.window_x,
|
0x4B => self.ppu.pos.window_x,
|
||||||
0x4D => 0xFF, // CGB Specific Register
|
0x4D => 0xFF, // CGB Specific Register
|
||||||
_ => unimplemented!("Unable to read {:#06X} in I/O Registers", addr),
|
_ => {
|
||||||
|
eprintln!("Read 0xFF from unused IO register {:#06X}.", addr);
|
||||||
|
0xFF
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xFF80..=0xFFFE => {
|
0xFF80..=0xFFFE => {
|
||||||
|
@ -339,13 +342,13 @@ impl BusIo for Bus {
|
||||||
0x06 => self.timer.modulo = byte,
|
0x06 => self.timer.modulo = byte,
|
||||||
0x07 => self.timer.ctrl = byte.into(),
|
0x07 => self.timer.ctrl = byte.into(),
|
||||||
0x0F => self.set_interrupt_flag(byte),
|
0x0F => self.set_interrupt_flag(byte),
|
||||||
0x10 => self.apu.ch1.sweep = byte.into(),
|
0x10 => self.apu.ch1.set_sweep(byte),
|
||||||
0x11 => self.apu.ch1.set_duty(byte),
|
0x11 => self.apu.ch1.set_duty(byte),
|
||||||
0x12 => self.apu.ch1.envelope = byte.into(),
|
0x12 => self.apu.ch1.set_envelope(byte),
|
||||||
0x13 => self.apu.ch1.set_freq_lo(byte),
|
0x13 => self.apu.ch1.set_freq_lo(byte),
|
||||||
0x14 => self.apu.ch1.set_freq_hi(byte),
|
0x14 => self.apu.ch1.set_freq_hi(byte),
|
||||||
0x16 => self.apu.ch2.set_duty(byte),
|
0x16 => self.apu.ch2.set_duty(byte),
|
||||||
0x17 => self.apu.ch2.envelope = byte.into(),
|
0x17 => self.apu.ch2.set_envelope(byte),
|
||||||
0x18 => self.apu.ch2.set_freq_lo(byte),
|
0x18 => self.apu.ch2.set_freq_lo(byte),
|
||||||
0x19 => self.apu.ch2.set_freq_hi(byte),
|
0x19 => self.apu.ch2.set_freq_hi(byte),
|
||||||
0x1A => self.apu.ch3.set_enabled(byte),
|
0x1A => self.apu.ch3.set_enabled(byte),
|
||||||
|
@ -354,12 +357,12 @@ impl BusIo for Bus {
|
||||||
0x1D => self.apu.ch3.set_freq_lo(byte),
|
0x1D => self.apu.ch3.set_freq_lo(byte),
|
||||||
0x1E => self.apu.ch3.set_freq_hi(byte),
|
0x1E => self.apu.ch3.set_freq_hi(byte),
|
||||||
0x20 => self.apu.ch4.set_len(byte),
|
0x20 => self.apu.ch4.set_len(byte),
|
||||||
0x21 => self.apu.ch4.envelope = byte.into(),
|
0x21 => self.apu.ch4.set_envelope(byte),
|
||||||
0x22 => self.apu.ch4.poly = byte.into(),
|
0x22 => self.apu.ch4.set_poly(byte),
|
||||||
0x23 => self.apu.ch4.set_freq_data(byte),
|
0x23 => self.apu.ch4.set_freq_data(byte),
|
||||||
0x24 => self.apu.ctrl.channel = byte.into(),
|
0x24 => self.apu.ctrl.set_channel(byte),
|
||||||
0x25 => self.apu.ctrl.output = byte.into(),
|
0x25 => self.apu.ctrl.set_output(byte),
|
||||||
0x26 => self.apu.ctrl.set_status(byte), // FIXME: Should we control which bytes are written to here?
|
0x26 => self.apu.set_status(byte),
|
||||||
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30] = byte,
|
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30] = byte,
|
||||||
0x40 => self.ppu.ctrl = byte.into(),
|
0x40 => self.ppu.ctrl = byte.into(),
|
||||||
0x41 => self.ppu.stat.update(byte),
|
0x41 => self.ppu.stat.update(byte),
|
||||||
|
@ -392,8 +395,7 @@ impl BusIo for Bus {
|
||||||
self.boot = None;
|
self.boot = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x7F => {} // Tetris tries to write to this non-existent IO Address
|
_ => eprintln!("Wrote {:#04X} to unused IO register {:#06X}.", byte, addr),
|
||||||
_ => unimplemented!("Unable to write to {:#06X} in I/O Registers", addr),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
0xFF80..=0xFFFE => {
|
0xFF80..=0xFFFE => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
|
||||||
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
|
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
|
||||||
use gb::{AudioMPSC, Cycle, Egui, GB_HEIGHT, GB_WIDTH};
|
use gb::{AudioMPSC, Cycle, Egui, GB_HEIGHT, GB_WIDTH};
|
||||||
use gilrs::Gilrs;
|
use gilrs::Gilrs;
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use pixels::{PixelsBuilder, SurfaceTexture};
|
||||||
use rodio::OutputStream;
|
use rodio::OutputStream;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use winit::dpi::LogicalSize;
|
use winit::dpi::LogicalSize;
|
||||||
|
@ -60,7 +60,10 @@ fn main() -> Result<()> {
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
let scale_factor = window.scale_factor();
|
let scale_factor = window.scale_factor();
|
||||||
let surface_texture = SurfaceTexture::new(size.width, size.height, &window);
|
let surface_texture = SurfaceTexture::new(size.width, size.height, &window);
|
||||||
let pixels = Pixels::new(GB_WIDTH as u32, GB_HEIGHT as u32, surface_texture)?;
|
|
||||||
|
let pixels = PixelsBuilder::new(GB_WIDTH as u32, GB_HEIGHT as u32, surface_texture)
|
||||||
|
.enable_vsync(false)
|
||||||
|
.build()?;
|
||||||
let egui = Egui::new(size.width, size.height, scale_factor, pixels.context());
|
let egui = Egui::new(size.width, size.height, scale_factor, pixels.context());
|
||||||
|
|
||||||
(pixels, egui)
|
(pixels, egui)
|
||||||
|
|
Loading…
Reference in New Issue