commodore64: SID waveform data is now in a lookup table, increases performance and startup time

This commit is contained in:
saxxonpike 2012-11-15 06:56:19 +00:00
parent b4ed1fa822
commit 94beebdbde
3 changed files with 4230 additions and 239 deletions

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public VoiceRegs() public VoiceRegs()
{ {
Envelope = new EnvelopeGenerator(); Envelope = new EnvelopeGenerator();
Generator = new WaveformGenerator(WaveformCalculator.BuildTable()); Generator = new WaveformGenerator();
} }
public void Clock() public void Clock()
@ -119,31 +119,35 @@ namespace BizHawk.Emulation.Computers.Commodore64
case 0x07: case 0x07:
case 0x0E: case 0x0E:
index = addr / 7; index = addr / 7;
Voices[index].Generator.WriteFreqLo(value); Voices[index].Generator.Frequency &= 0xFF00;
Voices[index].Generator.Frequency |= value;
break; break;
case 0x01: case 0x01:
case 0x08: case 0x08:
case 0x0F: case 0x0F:
index = addr / 7; index = addr / 7;
Voices[index].Generator.WriteFreqHi(value); Voices[index].Generator.Frequency &= 0xFF;
Voices[index].Generator.Frequency |= (int)value << 8;
break; break;
case 0x02: case 0x02:
case 0x09: case 0x09:
case 0x10: case 0x10:
index = addr / 7; index = addr / 7;
Voices[index].Generator.WritePWLo(value); Voices[index].Generator.PulseWidth &= 0x0F00;
Voices[index].Generator.PulseWidth |= value;
break; break;
case 0x03: case 0x03:
case 0x0A: case 0x0A:
case 0x11: case 0x11:
index = addr / 7; index = addr / 7;
Voices[index].Generator.WritePWHi(value); Voices[index].Generator.PulseWidth &= 0xFF;
Voices[index].Generator.PulseWidth |= (int)(value & 0xF) << 8;
break; break;
case 0x04: case 0x04:
case 0x0B: case 0x0B:
case 0x12: case 0x12:
index = addr / 7; index = addr / 7;
Voices[index].Generator.WriteControl(value); Voices[index].Generator.Control = value;
Voices[index].Envelope.Gate = ((value & 0x01) != 0x00); Voices[index].Envelope.Gate = ((value & 0x01) != 0x00);
break; break;
case 0x05: case 0x05:
@ -241,6 +245,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
voices[0].Clock(); voices[0].Clock();
voices[1].Clock(); voices[1].Clock();
voices[2].Clock(); voices[2].Clock();
// sync voices
voices[0].Generator.Synchronize(voices[1].Generator, voices[2].Generator);
voices[1].Generator.Synchronize(voices[2].Generator, voices[0].Generator);
voices[2].Generator.Synchronize(voices[0].Generator, voices[1].Generator);
// finalize sample and put into buffer
SubmitSample(); SubmitSample();
// query pots every 512 cycles // query pots every 512 cycles

View File

@ -9,32 +9,33 @@ namespace BizHawk.Emulation.Computers.Commodore64
// constants for the WaveformGenerator and calculation // constants for the WaveformGenerator and calculation
// methods come from the libsidplayfp residfp library. // methods come from the libsidplayfp residfp library.
public class WaveformGenerator public partial class WaveformGenerator
{ {
private int accumulator; private int accumulator;
private byte control;
private int floatingOutputTtl; private int floatingOutputTtl;
private int freq; private int freq;
private short[][] modelWave;
private bool msbRising; private bool msbRising;
private int noiseOutput; private int noiseOutput;
private int noNoise;
private int noNoiseOrNoiseOutput;
private int noPulse;
private int pulseOutput; private int pulseOutput;
private int pw; private int pw;
private int ringMsbMask; private int ringMsbMask;
private int shiftPipeline;
private int shiftRegister; private int shiftRegister;
private int shiftRegisterReset; private int shiftRegisterDelay;
private int shiftRegisterResetDelay;
private bool sync; private bool sync;
private bool test; private bool test;
private short[] wave; private short[] wave;
private int waveform; private int waveform;
private int waveformOutput; private int waveformOutput;
public WaveformGenerator(short[][] newModelWave) // these are temp values used to speed up calculation
private int noNoise;
private int noNoiseOrNoiseOutput;
private int noPulse;
public WaveformGenerator()
{ {
modelWave = newModelWave;
Reset(); Reset();
} }
@ -42,11 +43,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
{ {
if (test) if (test)
{ {
if (shiftRegisterReset != 0 && --shiftRegisterReset == 0) pulseOutput = 0xFFF;
if (shiftRegisterResetDelay != 0 && --shiftRegisterResetDelay == 0)
{ {
ResetShiftRegister(); ResetShiftRegister();
} }
pulseOutput = 0xFFF;
} }
else else
{ {
@ -58,9 +59,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
if ((accumulatorBitsSet & 0x080000) != 0) if ((accumulatorBitsSet & 0x080000) != 0)
{ {
shiftPipeline = 2; shiftRegisterDelay = 2;
} }
else if (shiftPipeline != 0 && --shiftPipeline == 0) else if (shiftRegisterDelay != 0 && --shiftRegisterDelay == 0)
{ {
ClockShiftRegister(); ClockShiftRegister();
} }
@ -71,7 +72,62 @@ namespace BizHawk.Emulation.Computers.Commodore64
{ {
int bit0 = ((shiftRegister >> 22) ^ (shiftRegister >> 17)) & 0x1; int bit0 = ((shiftRegister >> 22) ^ (shiftRegister >> 17)) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF; shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
SetNoiseOutput(); UpdateNoiseOutput();
}
public byte Control
{
get
{
return control;
}
set
{
control = value;
int waveformPrev = waveform;
bool testPrev = test;
waveform = (control >> 4) & 0x0F;
test = (control & 0x08) != 0;
sync = (control & 0x02) != 0;
wave = WaveformSamples[waveform & 0x7];
ringMsbMask = ((~control >> 5) & (control >> 2) & 0x1) << 23;
noNoise = (waveform & 0x8) != 0 ? 0x000 : 0xFFF;
noNoiseOrNoiseOutput = noNoise | noiseOutput;
noPulse = (waveform & 0x4) != 0 ? 0x000 : 0xFFF;
if (!testPrev && test)
{
accumulator = 0;
shiftRegisterDelay = 0;
shiftRegisterResetDelay = 0x8000;
}
else if (testPrev && !test)
{
int bit0 = (~shiftRegister >> 17) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
UpdateNoiseOutput();
}
if (waveform == 0 && waveformPrev != 0)
{
floatingOutputTtl = 0x28000;
}
}
}
public int Frequency
{
get
{
return freq;
}
set
{
freq = value;
}
} }
public short Output(WaveformGenerator ringModulator) public short Output(WaveformGenerator ringModulator)
@ -96,47 +152,39 @@ namespace BizHawk.Emulation.Computers.Commodore64
return (short)waveformOutput; return (short)waveformOutput;
} }
public int ReadAccumulator() public int PulseWidth
{ {
return accumulator; get
{
return pw;
} }
set
public int ReadFreq()
{ {
return freq; pw = value;
} }
public byte ReadOsc()
{
return (byte)(waveformOutput >> 4);
}
public bool ReadSync()
{
return sync;
}
public bool ReadTest()
{
return test;
} }
public void Reset() public void Reset()
{ {
accumulator = 0; control = 0;
waveform = 0;
freq = 0; freq = 0;
pw = 0; pw = 0;
msbRising = false; accumulator = 0;
waveform = 0;
test = false; test = false;
sync = false; sync = false;
wave = modelWave[0];
msbRising = false;
wave = WaveformSamples[0];
ringMsbMask = 0; ringMsbMask = 0;
noNoise = 0xFFF; noNoise = 0xFFF;
noPulse = 0xFFF; noPulse = 0xFFF;
pulseOutput = 0xFFF; pulseOutput = 0xFFF;
ResetShiftRegister(); ResetShiftRegister();
shiftPipeline = 0;
shiftRegisterDelay = 0;
waveformOutput = 0; waveformOutput = 0;
floatingOutputTtl = 0; floatingOutputTtl = 0;
} }
@ -144,11 +192,19 @@ namespace BizHawk.Emulation.Computers.Commodore64
private void ResetShiftRegister() private void ResetShiftRegister()
{ {
shiftRegister = 0x7FFFFF; shiftRegister = 0x7FFFFF;
shiftRegisterReset = 0; shiftRegisterResetDelay = 0;
SetNoiseOutput(); UpdateNoiseOutput();
} }
private void SetNoiseOutput() public void Synchronize(WaveformGenerator syncDest, WaveformGenerator syncSource)
{
if (msbRising && syncDest.sync && !(sync && syncSource.msbRising))
{
syncDest.accumulator = 0;
}
}
private void UpdateNoiseOutput()
{ {
noiseOutput = noiseOutput =
((shiftRegister & 0x100000) >> 9) | ((shiftRegister & 0x100000) >> 9) |
@ -162,71 +218,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
noNoiseOrNoiseOutput = noNoise | noiseOutput; noNoiseOrNoiseOutput = noNoise | noiseOutput;
} }
public void Synchronize(WaveformGenerator syncDest, WaveformGenerator syncSource)
{
if (msbRising && syncDest.sync && !(sync && syncSource.msbRising))
{
syncDest.accumulator = 0;
}
}
public void WriteControl(byte control)
{
int waveformPrev = waveform;
bool testPrev = test;
waveform = (control >> 4) & 0x0F;
test = (control & 0x08) != 0;
sync = (control & 0x02) != 0;
wave = modelWave[waveform & 0x7];
ringMsbMask = ((~control >> 5) & (control >> 2) & 0x1) << 23;
noNoise = (waveform & 0x8) != 0 ? 0x000 : 0xFFF;
noNoiseOrNoiseOutput = noNoise | noiseOutput;
noPulse = (waveform & 0x4) != 0 ? 0x000 : 0xFFF;
if (!testPrev && test)
{
accumulator = 0;
shiftPipeline = 0;
shiftRegisterReset = 0x8000;
}
else if (testPrev && !test)
{
int bit0 = (~shiftRegister >> 17) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
SetNoiseOutput();
}
if (waveform == 0 && waveformPrev != 0)
{
floatingOutputTtl = 0x28000;
}
}
public void WriteFreqLo(byte freqLo)
{
freq &= 0xFF00;
freq |= freqLo;
}
public void WriteFreqHi(byte freqHi)
{
freq &= 0x00FF;
freq |= (int)(freqHi << 8) & 0xFF00;
}
public void WritePWLo(byte pwLo)
{
pw &= 0x0F00;
pw |= pwLo;
}
public void WritePWHi(byte pwHi)
{
pw &= 0x00FF;
pw |= (int)(pwHi << 8) & 0x0F00;
}
private void WriteShiftRegister() private void WriteShiftRegister()
{ {
shiftRegister &= shiftRegister &=