Run SMP and DSP in less of a lockstep arrangement

CQTexperiment
Chris Moeller 2013-10-27 15:00:13 -07:00
parent 9211827957
commit 0a2dd30a51
7 changed files with 51 additions and 24 deletions

View File

@ -3,18 +3,25 @@
namespace SuperFamicom { namespace SuperFamicom {
void DSP::step(unsigned clocks) { void DSP::step(uint64_t clocks) {
clock += clocks; clock += clocks;
} }
void DSP::enter() { void DSP::enter() {
spc_dsp.run(1); int64_t dsp_clocks = (-clock) / (24 * 4096) + 1;
step(24 * 4096); spc_dsp.run(dsp_clocks);
step(dsp_clocks * 24 * 4096);
signed count = spc_dsp.sample_count(); signed count = spc_dsp.sample_count();
if(count > 0) { if(count > removed_samples) {
for(unsigned n = 0; n < count; n += 2) smp.sample(samplebuffer[n + 0], samplebuffer[n + 1]); 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); spc_dsp.set_output(samplebuffer, 8192);
removed_samples = 0;
} }
} }
@ -34,11 +41,13 @@ void DSP::power() {
spc_dsp.init(smp.apuram); spc_dsp.init(smp.apuram);
spc_dsp.reset(); spc_dsp.reset();
spc_dsp.set_output(samplebuffer, 8192); spc_dsp.set_output(samplebuffer, 8192);
removed_samples = 0;
} }
void DSP::reset() { void DSP::reset() {
spc_dsp.soft_reset(); spc_dsp.soft_reset();
spc_dsp.set_output(samplebuffer, 8192); spc_dsp.set_output(samplebuffer, 8192);
removed_samples = 0;
} }
void DSP::channel_enable(unsigned channel, bool enable) { void DSP::channel_enable(unsigned channel, bool enable) {
@ -55,7 +64,7 @@ void DSP::disable_surround(bool disable) {
} }
DSP::DSP(struct SMP & p_smp) 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; for(unsigned i = 0; i < 8; i++) channel_enabled[i] = true;
} }

View File

@ -9,8 +9,9 @@ namespace SuperFamicom {
struct DSP { struct DSP {
int64_t clock; int64_t clock;
unsigned long removed_samples;
inline void step(unsigned clocks); inline void step(uint64_t clocks);
bool mute(); bool mute();
uint8_t read(uint8_t addr); uint8_t read(uint8_t addr);

View File

@ -22,6 +22,14 @@ void SMP::port_write(uint8_t port, uint8_t data) {
uint8_t SMP::op_busread(uint16_t addr) { uint8_t SMP::op_busread(uint16_t addr) {
unsigned result; 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) { switch(addr) {
case 0xf0: //TEST -- write-only register case 0xf0: //TEST -- write-only register
return 0x00; return 0x00;
@ -34,6 +42,7 @@ uint8_t SMP::op_busread(uint16_t addr) {
case 0xf3: //DSPDATA case 0xf3: //DSPDATA
//0x80-0xff are read-only mirrors of 0x00-0x7f //0x80-0xff are read-only mirrors of 0x00-0x7f
synchronize_dsp();
return dsp.read(status.dsp_addr & 0x7f); return dsp.read(status.dsp_addr & 0x7f);
case 0xf4: //CPUIO0 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) { void SMP::op_buswrite(uint16_t addr, uint8_t data) {
synchronize_dsp();
switch(addr) { switch(addr) {
case 0xf0: //TEST case 0xf0: //TEST
if(regs.p.p) break; //writes only valid when P flag is clear if(regs.p.p) break; //writes only valid when P flag is clear

View File

@ -14,21 +14,26 @@ void SMP::step(unsigned clocks) {
} }
void SMP::synchronize_dsp() { void SMP::synchronize_dsp() {
while(dsp.clock < 0 && sample_buffer < sample_buffer_end) dsp.enter(); while(dsp.clock < 0) dsp.enter();
} }
void SMP::enter() { void SMP::enter() {
while(status.clock_speed != 2 && sample_buffer < sample_buffer_end) op_step(); while(sample_buffer < sample_buffer_end) {
if (status.clock_speed == 2) { 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(); 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) { 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 = buffer;
sample_buffer_end = buffer + count; sample_buffer_end = buffer + count;
enter(); enter();
@ -46,14 +51,16 @@ void SMP::skip(unsigned count) {
enter(); 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 > ((const int16_t *)0) + 4096 ) {
if ( sample_buffer < sample_buffer_end ) *sample_buffer++ = left; *sample_buffer++ = left;
if ( sample_buffer < sample_buffer_end ) *sample_buffer++ = right; *sample_buffer++ = right;
} }
else if ( sample_buffer < sample_buffer_end ){ else {
sample_buffer += 2; sample_buffer += 2;
} }
return true;
} }
void SMP::power() { void SMP::power() {

View File

@ -47,7 +47,7 @@ private:
int16_t * sample_buffer; int16_t * sample_buffer;
int16_t const* sample_buffer_end; int16_t const* sample_buffer_end;
public: public:
void sample( int16_t, int16_t ); bool sample( int16_t, int16_t );
SMP(); SMP();
~SMP(); ~SMP();

View File

@ -2,7 +2,7 @@
void SMP::add_clocks(unsigned clocks) { void SMP::add_clocks(unsigned clocks) {
step(clocks); step(clocks);
synchronize_dsp(); //synchronize_dsp();
} }
void SMP::cycle_edge() { void SMP::cycle_edge() {