troubleshooting, experimenting

This commit is contained in:
Theron Spiegl 2019-12-31 17:22:44 -06:00
parent f936258310
commit 8f3ab6e751
3 changed files with 17 additions and 5 deletions

View File

@ -60,8 +60,6 @@ impl Apu {
pub fn new() -> Self {
let square_table = (0..31).map(|x| 95.52/((8128.0 / x as f32) + 100.0)).collect();
let tnd_table = (0..203).map(|x| 163.67/((24329.0 / x as f32) + 100.0)).collect();
println!("square_table: {:?}", square_table);
println!("tnd_table: {:?}", tnd_table);
Apu {
square1: Square::new(false),
square2: Square::new(true),

View File

@ -80,7 +80,7 @@ impl Square {
// Update volume for this channel
// The mixer receives the current envelope volume except when
self.sample = if self.duty_cycle[self.duty_counter] == 0 // the sequencer output is zero, or
|| self.target_period > 0x7FF // overflow from the sweep unit's adder is silencing the channel,
|| self.timer_period > 0x7FF // overflow from the sweep unit's adder is silencing the channel,
|| self.length_counter == 0 // the length counter is zero, or
|| self.timer_period < 8 { // the timer has a value less than eight.
0
@ -126,9 +126,10 @@ impl Square {
}
pub fn clock_sweep(&mut self) {
self.calculate_target_period();
// When the frame counter sends a half-frame clock (at 120 or 96 Hz), two things happen.
// If the divider's counter is zero, the sweep is enabled, and the sweep unit is not muting the channel: The pulse's period is adjusted.
if self.sweep_counter == 0 && self.sweep_enabled && !(self.timer_period < 8 || self.target_period > 0x7FF) {
if self.sweep_counter == 0 && self.sweep_enabled && !(self.timer_period < 8 || self.timer_period > 0x7FF) {
self.timer_period = self.target_period;
println!("timer period adjusted to {}", self.timer_period);
}
@ -139,7 +140,10 @@ impl Square {
} else {
self.sweep_counter -= 1;
}
}
// Whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.
pub fn calculate_target_period(&mut self) {
// The sweep unit continuously calculates each channel's target period in this way:
// A barrel shifter shifts the channel's 11-bit raw timer period right by the shift count, producing the change amount.
let change = self.timer_period >> self.shift_count;
@ -185,17 +189,21 @@ impl Square {
pub fn write_timer_low(&mut self, value: u8) {
self.timer_period &= 0b00000111_00000000; // mask off everything but high 3 bits of 11-bit timer
self.timer_period |= value as u16; // apply low 8 bits
self.calculate_target_period();
}
// $4003/$4007
pub fn write_timer_high(&mut self, value: u8) {
// LLLL.Lttt Pulse channel 1 length counter load and timer (write)
// TODO: thought the below meant that the length counter was only set if the channel was enabled, but apparently not as not having it fixes start game noise in DK.
// When the enabled bit is cleared (via $4015), the length counter is forced to 0 and cannot be changed until enabled is set again (the length counter's previous value is lost).
if self.enabled {
self.length_counter = super::LENGTH_COUNTER_TABLE[value as usize >> 3];
}
let timer_high = value as u16 & 0b0000_0111;
self.timer_period &= 0b11111000_11111111; // mask off high 3 bits of 11-bit timer
self.timer_period |= timer_high << 8; // apply high timer bits in their place
self.calculate_target_period();
// The sequencer is immediately restarted at the first value of the current sequence. The envelope is also restarted. The period divider is not reset.
self.duty_counter = 0;
self.start = true;

View File

@ -69,7 +69,7 @@ fn main() -> Result<(), String> {
match cpu.apu.clock() {
Some(sample) => {
sps += 1;
audio_device.queue(&vec![sample]);
if sps < 44100 {audio_device.queue(&vec![sample]);}
},
None => (),
};
@ -126,8 +126,14 @@ TODO:
- remaining APU channels
- common mappers
- battery-backed RAM solution
- fix mysterious Mario pipe non-locations
- GUI? drag and drop ROMs?
- reset function
- save/load/pause functionality
Timing notes:
The PPU is throttled to 60Hz by sleeping in the main loop. This locks the CPU to roughly its intended speed, 1.789773MHz NTSC. The APU runs at half that.
The SDL audio device samples/outputs at 44,100Hz, so as long as the APU queues up 44,100 samples per second, it works.
*/