From 0a2dd30a51b5e444545b35ba4697aedfb3971463 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Sun, 27 Oct 2013 15:00:13 -0700 Subject: [PATCH] Run SMP and DSP in less of a lockstep arrangement --- Frameworks/GME/gme/higan/dsp/SPC_DSP.h | 8 +++---- Frameworks/GME/gme/higan/dsp/dsp.cpp | 21 +++++++++++++----- Frameworks/GME/gme/higan/dsp/dsp.hpp | 3 ++- Frameworks/GME/gme/higan/smp/memory.cpp | 10 +++++++++ Frameworks/GME/gme/higan/smp/smp.cpp | 29 +++++++++++++++---------- Frameworks/GME/gme/higan/smp/smp.hpp | 2 +- Frameworks/GME/gme/higan/smp/timing.cpp | 2 +- 7 files changed, 51 insertions(+), 24 deletions(-) diff --git a/Frameworks/GME/gme/higan/dsp/SPC_DSP.h b/Frameworks/GME/gme/higan/dsp/SPC_DSP.h index 84552991f..cc6c6d08d 100755 --- a/Frameworks/GME/gme/higan/dsp/SPC_DSP.h +++ b/Frameworks/GME/gme/higan/dsp/SPC_DSP.h @@ -198,9 +198,9 @@ public: unsigned read_counter( int rate ); int interpolate( voice_t const* v ); - int interpolate_cubic( voice_t const* v ); - int interpolate_sinc( voice_t const* v ); - int interpolate_linear( voice_t const* v ); + int interpolate_cubic( voice_t const* v ); + int interpolate_sinc( voice_t const* v ); + int interpolate_linear( voice_t const* v ); int interpolate_nearest( voice_t const* v ); void run_envelope( voice_t* const v ); @@ -250,7 +250,7 @@ public: #include inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } - + inline int SPC_DSP::read( int addr ) const { assert( (unsigned) addr < register_count ); diff --git a/Frameworks/GME/gme/higan/dsp/dsp.cpp b/Frameworks/GME/gme/higan/dsp/dsp.cpp index 6efc006fe..2ed8827c9 100755 --- a/Frameworks/GME/gme/higan/dsp/dsp.cpp +++ b/Frameworks/GME/gme/higan/dsp/dsp.cpp @@ -3,18 +3,25 @@ namespace SuperFamicom { -void DSP::step(unsigned clocks) { +void DSP::step(uint64_t clocks) { clock += clocks; } void DSP::enter() { - spc_dsp.run(1); - step(24 * 4096); + int64_t dsp_clocks = (-clock) / (24 * 4096) + 1; + spc_dsp.run(dsp_clocks); + step(dsp_clocks * 24 * 4096); signed count = spc_dsp.sample_count(); - if(count > 0) { - for(unsigned n = 0; n < count; n += 2) smp.sample(samplebuffer[n + 0], samplebuffer[n + 1]); + if(count > removed_samples) { + for(unsigned n = removed_samples; n < count; n += 2) { + if (!smp.sample(samplebuffer[n + 0], samplebuffer[n + 1])) { + removed_samples = n; + return; + } + } spc_dsp.set_output(samplebuffer, 8192); + removed_samples = 0; } } @@ -34,11 +41,13 @@ void DSP::power() { spc_dsp.init(smp.apuram); spc_dsp.reset(); spc_dsp.set_output(samplebuffer, 8192); + removed_samples = 0; } void DSP::reset() { spc_dsp.soft_reset(); spc_dsp.set_output(samplebuffer, 8192); + removed_samples = 0; } void DSP::channel_enable(unsigned channel, bool enable) { @@ -55,7 +64,7 @@ void DSP::disable_surround(bool disable) { } DSP::DSP(struct SMP & p_smp) - : smp( p_smp ), clock( 0 ) { + : smp( p_smp ), clock( 0 ), removed_samples( 0 ) { for(unsigned i = 0; i < 8; i++) channel_enabled[i] = true; } diff --git a/Frameworks/GME/gme/higan/dsp/dsp.hpp b/Frameworks/GME/gme/higan/dsp/dsp.hpp index 7758ed0d5..dce3cdc02 100755 --- a/Frameworks/GME/gme/higan/dsp/dsp.hpp +++ b/Frameworks/GME/gme/higan/dsp/dsp.hpp @@ -9,8 +9,9 @@ namespace SuperFamicom { struct DSP { int64_t clock; + unsigned long removed_samples; - inline void step(unsigned clocks); + inline void step(uint64_t clocks); bool mute(); uint8_t read(uint8_t addr); diff --git a/Frameworks/GME/gme/higan/smp/memory.cpp b/Frameworks/GME/gme/higan/smp/memory.cpp index d390834d5..51cabad92 100755 --- a/Frameworks/GME/gme/higan/smp/memory.cpp +++ b/Frameworks/GME/gme/higan/smp/memory.cpp @@ -22,6 +22,14 @@ void SMP::port_write(uint8_t port, uint8_t data) { uint8_t SMP::op_busread(uint16_t addr) { unsigned result; + if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) { + int start = 0x100 * dsp.read( SPC_DSP::r_esa ); + int end = start + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); + if ( end > 0x10000 ) + end = 0x10000; + if ( addr >= start || addr < end) synchronize_dsp(); + } + switch(addr) { case 0xf0: //TEST -- write-only register return 0x00; @@ -34,6 +42,7 @@ uint8_t SMP::op_busread(uint16_t addr) { case 0xf3: //DSPDATA //0x80-0xff are read-only mirrors of 0x00-0x7f + synchronize_dsp(); return dsp.read(status.dsp_addr & 0x7f); case 0xf4: //CPUIO0 @@ -77,6 +86,7 @@ uint8_t SMP::op_busread(uint16_t addr) { } void SMP::op_buswrite(uint16_t addr, uint8_t data) { + synchronize_dsp(); switch(addr) { case 0xf0: //TEST if(regs.p.p) break; //writes only valid when P flag is clear diff --git a/Frameworks/GME/gme/higan/smp/smp.cpp b/Frameworks/GME/gme/higan/smp/smp.cpp index 8ed285047..a46a9ffca 100755 --- a/Frameworks/GME/gme/higan/smp/smp.cpp +++ b/Frameworks/GME/gme/higan/smp/smp.cpp @@ -14,21 +14,26 @@ void SMP::step(unsigned clocks) { } void SMP::synchronize_dsp() { - while(dsp.clock < 0 && sample_buffer < sample_buffer_end) dsp.enter(); + while(dsp.clock < 0) dsp.enter(); } void SMP::enter() { - while(status.clock_speed != 2 && sample_buffer < sample_buffer_end) op_step(); - if (status.clock_speed == 2) { + while(sample_buffer < sample_buffer_end) { + clock -= (sample_buffer_end - sample_buffer) * 24 * 16; + while(status.clock_speed != 2 && clock < 0) op_step(); + if(status.clock_speed == 2) step(-clock); synchronize_dsp(); - if (sample_buffer < sample_buffer_end) { - dsp.clock -= 24 * 32 * (sample_buffer_end - sample_buffer) / 2; - synchronize_dsp(); - } } } void SMP::render(int16_t * buffer, unsigned count) { + while (count > 4096) { + sample_buffer = buffer; + sample_buffer_end = buffer + 4096; + buffer += 4096; + count -= 4096; + enter(); + } sample_buffer = buffer; sample_buffer_end = buffer + count; enter(); @@ -46,14 +51,16 @@ void SMP::skip(unsigned count) { enter(); } -void SMP::sample(int16_t left, int16_t right) { +bool SMP::sample(int16_t left, int16_t right) { + if ( sample_buffer_end - sample_buffer < 2 ) return false; if ( sample_buffer > ((const int16_t *)0) + 4096 ) { - if ( sample_buffer < sample_buffer_end ) *sample_buffer++ = left; - if ( sample_buffer < sample_buffer_end ) *sample_buffer++ = right; + *sample_buffer++ = left; + *sample_buffer++ = right; } - else if ( sample_buffer < sample_buffer_end ){ + else { sample_buffer += 2; } + return true; } void SMP::power() { diff --git a/Frameworks/GME/gme/higan/smp/smp.hpp b/Frameworks/GME/gme/higan/smp/smp.hpp index 6c3a6f899..ffc1e351e 100755 --- a/Frameworks/GME/gme/higan/smp/smp.hpp +++ b/Frameworks/GME/gme/higan/smp/smp.hpp @@ -47,7 +47,7 @@ private: int16_t * sample_buffer; int16_t const* sample_buffer_end; public: - void sample( int16_t, int16_t ); + bool sample( int16_t, int16_t ); SMP(); ~SMP(); diff --git a/Frameworks/GME/gme/higan/smp/timing.cpp b/Frameworks/GME/gme/higan/smp/timing.cpp index bdd27e406..64265ab70 100755 --- a/Frameworks/GME/gme/higan/smp/timing.cpp +++ b/Frameworks/GME/gme/higan/smp/timing.cpp @@ -2,7 +2,7 @@ void SMP::add_clocks(unsigned clocks) { step(clocks); - synchronize_dsp(); + //synchronize_dsp(); } void SMP::cycle_edge() {