Compare commits

..

No commits in common. "a77d0a0f62aa62032a3bc21c7f37f25e3775d5b1" and "5d6df46a2d6ab4f1457f3d8b288e69250521a5fc" have entirely different histories.

6 changed files with 152 additions and 83 deletions

View File

@ -5,7 +5,7 @@ use types::ch1::{Sweep, SweepDirection};
use types::ch3::Volume as Ch3Volume; use types::ch3::Volume as Ch3Volume;
use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter}; use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter};
use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope}; use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope};
use types::{ChannelControl, SoundOutput}; use types::{ChannelControl, FrameSequencerState, SoundOutput};
pub mod gen; pub mod gen;
mod types; mod types;
@ -26,7 +26,8 @@ pub struct Apu {
ch4: Channel4, ch4: Channel4,
// Frame Sequencer // Frame Sequencer
div_prev: Option<u16>, frame_seq_state: FrameSequencerState,
div_prev: Option<u8>,
prod: Option<SampleProducer<f32>>, prod: Option<SampleProducer<f32>>,
sample_counter: u64, sample_counter: u64,
@ -94,30 +95,41 @@ impl BusIo for Apu {
impl Apu { impl Apu {
pub(crate) fn tick(&mut self, div: u16) { pub(crate) fn tick(&mut self, div: u16) {
use FrameSequencerState::*;
self.sample_counter += SAMPLE_INCREMENT; self.sample_counter += SAMPLE_INCREMENT;
// Length Control (256Hz) // the 5th bit of the high byte
if self.falling_edge(13, div) { let bit_5 = (div >> 13 & 0x01) as u8;
self.handle_length();
}
// Sweep (128Hz) if let Some(0x01) = self.div_prev {
if self.falling_edge(14, div) { if bit_5 == 0x00 {
self.handle_sweep(); // Falling Edge, step the Frame Sequencer
} self.frame_seq_state.step();
// Volume Envelope (64Hz) match self.frame_seq_state {
if self.falling_edge(15, div) { Step0Length => self.handle_length(),
self.handle_volume(); Step2LengthAndSweep => {
self.handle_length();
self.handle_sweep();
}
Step4Length => self.handle_length(),
Step6LengthAndSweep => {
self.handle_length();
self.handle_sweep();
}
Step7VolumeEnvelope => self.handle_volume(),
Step1Nothing | Step3Nothing | Step5Nothing => {}
};
}
} }
self.div_prev = Some(div);
self.ch1.clock(); self.ch1.clock();
self.ch2.clock(); self.ch2.clock();
self.ch3.clock(); self.ch3.clock();
self.ch4.clock(); self.ch4.clock();
self.div_prev = Some(bit_5);
if self.sample_counter >= SM83_CLOCK_SPEED { if self.sample_counter >= SM83_CLOCK_SPEED {
self.sample_counter %= SM83_CLOCK_SPEED; self.sample_counter %= SM83_CLOCK_SPEED;
@ -164,8 +176,7 @@ impl Apu {
if self.ctrl.enabled { if self.ctrl.enabled {
// Frame Sequencer reset to Step 0 // Frame Sequencer reset to Step 0
// TODO: With the current implementation of the frame sequencer, self.frame_seq_state = Default::default();
// what does this even mean?
// Square Duty units are reset to first step // Square Duty units are reset to first step
self.ch1.duty_pos = 0; self.ch1.duty_pos = 0;
@ -327,13 +338,6 @@ impl Apu {
&mut self.ch4.current_volume, &mut self.ch4.current_volume,
); );
} }
fn falling_edge(&self, bit: u8, div: u16) -> bool {
match self.div_prev {
Some(p) => (p >> bit & 0x01) == 0x01 && (div >> bit & 0x01) == 0x00,
None => false,
}
}
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]

View File

@ -427,6 +427,41 @@ pub(crate) mod common {
} }
} }
#[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! { bitfield! {
pub struct SoundOutput(u8); pub struct SoundOutput(u8);
impl Debug; impl Debug;

View File

@ -104,10 +104,10 @@ impl Cpu {
Instruction::execute(self, instruction) Instruction::execute(self, instruction)
} }
/// Perform the [`Cpu::fetch()`] [`Cpu::decode()`] [`Cpu::execute()`] /// Perform the [`Cpu::fetch()`] [`Cpu::decode(opcode)`] [`Cpu::execute(instr)`]
/// routine. /// routine.
/// ///
/// Handle HALT and interrupts. /// Handle HALT state and interrupts.
pub fn step(&mut self) -> Cycle { pub fn step(&mut self) -> Cycle {
// Log instructions // Log instructions
// if self.reg.pc > 0xFF { // if self.reg.pc > 0xFF {

View File

@ -1531,8 +1531,7 @@ impl Instruction {
/// Set program counter to Address. /// Set program counter to Address.
/// ///
/// This is explicitly meant to emulate the exact behaviour of [`Instruction::JP`], [`Instruction::JR`] /// This is explicitly meant to emulate the exact behaviour of JP, JR RET, RETI and CALL
/// [`Instruction::RET`], [`Instruction::RETI`]
/// (4 cycles) /// (4 cycles)
fn jump(cpu: &mut Cpu, addr: u16) { fn jump(cpu: &mut Cpu, addr: u16) {
cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_register_pair(RegisterPair::PC, addr);

View File

@ -75,7 +75,7 @@ fn main() -> Result<()> {
}); });
let mut start = Instant::now(); let mut start = Instant::now();
let frame_time = Duration::from_secs_f64(1.0 / 59.73); // 59.73 Hz on Host let frame_time = Duration::from_secs_f64(1.0 / 60.0); // 60 Hz on Host
let mut cycle_count: Cycle = Default::default(); let mut cycle_count: Cycle = Default::default();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {

View File

@ -231,23 +231,20 @@ impl Ppu {
fn draw(&mut self, _cycle: u32) { fn draw(&mut self, _cycle: u32) {
use FetcherState::*; use FetcherState::*;
let mut iter = self.obj_buffer.iter_mut(); let iter = &mut self.obj_buffer.iter();
let default = &mut None;
let obj_attr = loop { let obj_attr = loop {
match iter.next() { match iter.flatten().next() {
Some(attr_opt) => { Some(attr) => {
if let Some(attr) = attr_opt { if attr.x <= (self.x_pos + 8) {
if attr.x <= (self.x_pos + 8) { self.fetch.back.reset();
self.fetch.back.reset(); self.fetch.back.pause();
self.fetch.back.pause(); self.fifo.pause();
self.fifo.pause();
break attr_opt; break Some(*attr);
}
} }
} }
None => break default, None => break None,
} }
}; };
@ -255,10 +252,10 @@ impl Ppu {
match self.fetch.obj.state { match self.fetch.obj.state {
TileNumber => { TileNumber => {
self.fetch.obj.tile.with_id(attr.tile_index); self.fetch.obj.tile.with_id(attr.tile_index);
self.fetch.obj.next(SleepOne); self.fetch.obj.next(ToLowByteSleep);
} }
SleepOne => self.fetch.obj.next(TileLow), ToLowByteSleep => self.fetch.obj.next(TileLowByte),
TileLow => { TileLowByte => {
let obj_size = self.ctrl.obj_size(); let obj_size = self.ctrl.obj_size();
let addr = PixelFetcher::get_obj_addr(&attr, &self.pos, obj_size); let addr = PixelFetcher::get_obj_addr(&attr, &self.pos, obj_size);
@ -266,10 +263,10 @@ impl Ppu {
let byte = self.read_byte(addr); let byte = self.read_byte(addr);
self.fetch.obj.tile.with_low_byte(byte); self.fetch.obj.tile.with_low_byte(byte);
self.fetch.obj.next(SleepTwo); self.fetch.obj.next(ToHighByteSleep);
} }
SleepTwo => self.fetch.obj.next(TileHigh), ToHighByteSleep => self.fetch.obj.next(TileHighByte),
TileHigh => { TileHighByte => {
let obj_size = self.ctrl.obj_size(); let obj_size = self.ctrl.obj_size();
let addr = PixelFetcher::get_obj_addr(&attr, &self.pos, obj_size); let addr = PixelFetcher::get_obj_addr(&attr, &self.pos, obj_size);
@ -277,10 +274,10 @@ impl Ppu {
let byte = self.read_byte(addr + 1); let byte = self.read_byte(addr + 1);
self.fetch.obj.tile.with_high_byte(byte); self.fetch.obj.tile.with_high_byte(byte);
self.fetch.obj.next(SleepThree); self.fetch.obj.next(ToFifoSleep);
} }
SleepThree => self.fetch.obj.next(ToFifoOne), ToFifoSleep => self.fetch.obj.next(SendToFifoOne),
ToFifoOne => { SendToFifoOne => {
// Load into Fifo // Load into Fifo
let (high, low) = self let (high, low) = self
.fetch .fetch
@ -292,12 +289,13 @@ impl Ppu {
let tbpp = Pixels::from_bytes(high, low); let tbpp = Pixels::from_bytes(high, low);
let palette_kind = attr.flags.palette(); let palette_kind = attr.flags.palette();
let end = Pixels::PIXEL_COUNT - self.fifo.obj.len();
let start = Pixels::PIXEL_COUNT - end;
let x_flip = attr.flags.x_flip(); let x_flip = attr.flags.x_flip();
let pixel_count = (attr.x - self.x_pos) as usize; for i in start..Pixels::PIXEL_COUNT {
let start = self.fifo.obj.len();
for i in start..pixel_count {
let x = if x_flip { 7 - i } else { i }; let x = if x_flip { 7 - i } else { i };
let priority = attr.flags.priority(); let priority = attr.flags.priority();
@ -314,11 +312,11 @@ impl Ppu {
self.fetch.back.resume(); self.fetch.back.resume();
self.fifo.resume(); self.fifo.resume();
let _ = std::mem::take(obj_attr); self.obj_buffer.remove(&attr);
self.fetch.obj.next(ToFifoTwo); self.fetch.obj.next(SendToFifoTwo);
} }
ToFifoTwo => self.fetch.obj.reset(), SendToFifoTwo => self.fetch.obj.reset(),
} }
} }
@ -348,31 +346,31 @@ impl Ppu {
self.fetch.back.tile.with_id(id); self.fetch.back.tile.with_id(id);
// Move on to the Next state in 2 T-cycles // Move on to the Next state in 2 T-cycles
self.fetch.back.next(SleepOne); self.fetch.back.next(ToLowByteSleep);
} }
SleepOne => self.fetch.back.next(TileLow), ToLowByteSleep => self.fetch.back.next(TileLowByte),
TileLow => { TileLowByte => {
let addr = self.fetch.bg_byte_addr(&self.ctrl, &self.pos); let addr = self.fetch.bg_byte_addr(&self.ctrl, &self.pos);
let low = self.read_byte(addr); let low = self.read_byte(addr);
self.fetch.back.tile.with_low_byte(low); self.fetch.back.tile.with_low_byte(low);
self.fetch.back.next(SleepTwo); self.fetch.back.next(ToHighByteSleep);
} }
SleepTwo => self.fetch.back.next(TileHigh), ToHighByteSleep => self.fetch.back.next(TileHighByte),
TileHigh => { TileHighByte => {
let addr = self.fetch.bg_byte_addr(&self.ctrl, &self.pos); let addr = self.fetch.bg_byte_addr(&self.ctrl, &self.pos);
let high = self.read_byte(addr + 1); let high = self.read_byte(addr + 1);
self.fetch.back.tile.with_high_byte(high); self.fetch.back.tile.with_high_byte(high);
self.fetch.back.next(SleepThree); self.fetch.back.next(ToFifoSleep);
} }
SleepThree => self.fetch.back.next(ToFifoOne), ToFifoSleep => self.fetch.back.next(SendToFifoOne),
ToFifoOne => { SendToFifoOne => {
self.fetch.back.next(ToFifoTwo); self.fetch.back.next(SendToFifoTwo);
} }
ToFifoTwo => { SendToFifoTwo => {
if let Ok(()) = self.fetch.send_to_fifo(&mut self.fifo) { if let Ok(()) = self.fetch.send_to_fifo(&mut self.fifo) {
self.fetch.x_pos += 1; self.fetch.x_pos += 1;
self.fetch.back.next(TileNumber); self.fetch.back.next(TileNumber);
@ -383,12 +381,12 @@ impl Ppu {
} }
if self.fifo.is_enabled() { if self.fifo.is_enabled() {
if self.x_pos == 0 && self.scanline_start { if self.x_pos == 0 && !self.fifo.back.is_empty() && self.scanline_start {
self.to_discard = self.pos.scroll_x % 8; self.to_discard = self.pos.scroll_x % 8;
self.scanline_start = false; self.scanline_start = false;
} }
if self.to_discard > 0 && !self.fifo.back.is_empty() { if self.to_discard > 0 {
let _ = self.fifo.back.pop_front(); let _ = self.fifo.back.pop_front();
self.to_discard -= 1; self.to_discard -= 1;
@ -610,34 +608,67 @@ impl<'a> From<&'a [u8; 4]> for ObjectAttribute {
#[derive(Debug)] #[derive(Debug)]
struct ObjectBuffer { struct ObjectBuffer {
inner: [Option<ObjectAttribute>; OBJECT_LIMIT], buf: [Option<ObjectAttribute>; OBJECT_LIMIT],
len: usize, len: usize,
} }
impl ObjectBuffer {
fn iter(&self) -> std::slice::Iter<'_, Option<ObjectAttribute>> {
self.into_iter()
}
}
impl<'a> IntoIterator for &'a ObjectBuffer {
type Item = &'a Option<ObjectAttribute>;
type IntoIter = std::slice::Iter<'a, Option<ObjectAttribute>>;
fn into_iter(self) -> Self::IntoIter {
self.buf.iter()
}
}
impl<'a> IntoIterator for &'a mut ObjectBuffer {
type Item = &'a Option<ObjectAttribute>;
type IntoIter = std::slice::Iter<'a, Option<ObjectAttribute>>;
fn into_iter(self) -> Self::IntoIter {
self.buf.iter()
}
}
impl ObjectBuffer { impl ObjectBuffer {
fn is_full(&self) -> bool { fn is_full(&self) -> bool {
self.len == OBJECT_LIMIT self.len == OBJECT_LIMIT
} }
fn clear(&mut self) { fn clear(&mut self) {
self.inner = [Default::default(); 10]; self.buf = [Default::default(); 10];
self.len = 0; self.len = 0;
} }
fn add(&mut self, attr: ObjectAttribute) { fn add(&mut self, attr: ObjectAttribute) {
self.inner[self.len] = Some(attr); self.buf[self.len] = Some(attr);
self.len += 1; self.len += 1;
} }
fn iter_mut(&mut self) -> std::slice::IterMut<'_, Option<ObjectAttribute>> { fn remove(&mut self, attr: &ObjectAttribute) {
self.inner.iter_mut() let maybe_index = self.buf.iter().position(|maybe_attr| match maybe_attr {
Some(other_attr) => attr == other_attr,
None => false,
});
if let Some(i) = maybe_index {
self.buf[i] = None;
}
} }
} }
impl Default for ObjectBuffer { impl Default for ObjectBuffer {
fn default() -> Self { fn default() -> Self {
Self { Self {
inner: [Default::default(); OBJECT_LIMIT], buf: [Default::default(); OBJECT_LIMIT],
len: Default::default(), len: Default::default(),
} }
} }
@ -872,13 +903,13 @@ impl WindowLineCounter {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum FetcherState { enum FetcherState {
TileNumber, TileNumber,
SleepOne, ToLowByteSleep,
TileLow, TileLowByte,
SleepTwo, ToHighByteSleep,
TileHigh, TileHighByte,
SleepThree, ToFifoSleep,
ToFifoOne, SendToFifoOne,
ToFifoTwo, SendToFifoTwo,
} }
impl Default for FetcherState { impl Default for FetcherState {