347 lines
6.2 KiB
C#
347 lines
6.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using BizHawk.Common;
|
|
|
|
namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|
{
|
|
sealed public partial class Sid
|
|
{
|
|
sealed class Voice
|
|
{
|
|
int accBits;
|
|
int accNext;
|
|
int accumulator;
|
|
bool controlTestPrev;
|
|
int controlWavePrev;
|
|
int delay;
|
|
int floatOutputTTL;
|
|
int frequency;
|
|
bool msbRising;
|
|
int noise;
|
|
int noNoise;
|
|
int noNoiseOrNoise;
|
|
int noPulse;
|
|
int output;
|
|
int pulse;
|
|
int pulseWidth;
|
|
bool ringMod;
|
|
int ringMsbMask;
|
|
int shiftRegister;
|
|
int shiftRegisterReset;
|
|
bool sync;
|
|
bool test;
|
|
int[] wave;
|
|
int waveform;
|
|
int waveformIndex;
|
|
int[][] waveTable;
|
|
|
|
public Voice(int[][] newWaveTable)
|
|
{
|
|
waveTable = newWaveTable;
|
|
HardReset();
|
|
}
|
|
|
|
public void HardReset()
|
|
{
|
|
accumulator = 0;
|
|
delay = 0;
|
|
floatOutputTTL = 0;
|
|
frequency = 0;
|
|
msbRising = false;
|
|
noNoise = 0xFFF;
|
|
noPulse = 0xFFF;
|
|
output = 0x000;
|
|
pulse = 0xFFF;
|
|
pulseWidth = 0;
|
|
ringMsbMask = 0;
|
|
sync = false;
|
|
test = false;
|
|
wave = waveTable[0];
|
|
waveform = 0;
|
|
|
|
ResetShiftReg();
|
|
}
|
|
|
|
public void ExecutePhase2()
|
|
{
|
|
|
|
{
|
|
if (test)
|
|
{
|
|
if (shiftRegisterReset != 0 && --shiftRegisterReset == 0)
|
|
{
|
|
ResetShiftReg();
|
|
}
|
|
pulse = 0xFFF;
|
|
}
|
|
else
|
|
{
|
|
accNext = (accumulator + frequency) & 0xFFFFFF;
|
|
accBits = ~accumulator & accNext;
|
|
accumulator = accNext;
|
|
msbRising = ((accBits & 0x800000) != 0);
|
|
|
|
if ((accBits & 0x080000) != 0)
|
|
delay = 2;
|
|
else if (delay != 0 && --delay == 0)
|
|
ClockShiftReg();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
private void ClockShiftReg()
|
|
{
|
|
|
|
{
|
|
shiftRegister = ((shiftRegister << 1) |
|
|
(((shiftRegister >> 22) ^ (shiftRegister >> 17)) & 0x1)
|
|
) & 0x7FFFFF;
|
|
SetNoise();
|
|
}
|
|
}
|
|
|
|
private void ResetShiftReg()
|
|
{
|
|
|
|
{
|
|
shiftRegister = 0x7FFFFF;
|
|
shiftRegisterReset = 0;
|
|
SetNoise();
|
|
}
|
|
}
|
|
|
|
private void SetNoise()
|
|
{
|
|
|
|
{
|
|
noise =
|
|
((shiftRegister & 0x100000) >> 9) |
|
|
((shiftRegister & 0x040000) >> 8) |
|
|
((shiftRegister & 0x004000) >> 5) |
|
|
((shiftRegister & 0x000800) >> 3) |
|
|
((shiftRegister & 0x000200) >> 2) |
|
|
((shiftRegister & 0x000020) << 1) |
|
|
((shiftRegister & 0x000004) << 3) |
|
|
((shiftRegister & 0x000001) << 4);
|
|
noNoiseOrNoise = noNoise | noise;
|
|
}
|
|
}
|
|
|
|
private void WriteShiftReg()
|
|
{
|
|
|
|
{
|
|
output &=
|
|
0xBB5DA |
|
|
((output & 0x800) << 9) |
|
|
((output & 0x400) << 8) |
|
|
((output & 0x200) << 5) |
|
|
((output & 0x100) << 3) |
|
|
((output & 0x040) >> 1) |
|
|
((output & 0x020) >> 3) |
|
|
((output & 0x010) >> 4);
|
|
noise &= output;
|
|
noNoiseOrNoise = noNoise | noise;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
public int Control
|
|
{
|
|
set
|
|
{
|
|
controlWavePrev = waveform;
|
|
controlTestPrev = test;
|
|
|
|
sync = ((value & 0x02) != 0);
|
|
ringMod = ((value & 0x04) != 0);
|
|
test = ((value & 0x08) != 0);
|
|
waveform = (value >> 4) & 0x0F;
|
|
wave = waveTable[waveform & 0x07];
|
|
ringMsbMask = ((~value >> 5) & (value >> 2) & 0x1) << 23;
|
|
noNoise = ((waveform & 0x8) != 0) ? 0x000 : 0xFFF;
|
|
noNoiseOrNoise = noNoise | noise;
|
|
noPulse = ((waveform & 0x4) != 0) ? 0x000 : 0xFFF;
|
|
|
|
if (!controlTestPrev && test)
|
|
{
|
|
accumulator = 0;
|
|
delay = 0;
|
|
shiftRegisterReset = 0x8000;
|
|
}
|
|
else if (controlTestPrev && !test)
|
|
{
|
|
shiftRegister = ((shiftRegister << 1) |
|
|
((~shiftRegister >> 17) & 0x1)
|
|
) & 0x7FFFFF;
|
|
SetNoise();
|
|
}
|
|
|
|
if (waveform == 0 && controlWavePrev != 0)
|
|
floatOutputTTL = 0x28000;
|
|
}
|
|
}
|
|
|
|
public int Frequency
|
|
{
|
|
get
|
|
{
|
|
return frequency;
|
|
}
|
|
set
|
|
{
|
|
frequency = value;
|
|
}
|
|
}
|
|
|
|
public int FrequencyLo
|
|
{
|
|
get
|
|
{
|
|
return (frequency & 0xFF);
|
|
}
|
|
set
|
|
{
|
|
frequency &= 0xFF00;
|
|
frequency |= value & 0x00FF;
|
|
}
|
|
}
|
|
|
|
public int FrequencyHi
|
|
{
|
|
get
|
|
{
|
|
return (frequency >> 8);
|
|
}
|
|
set
|
|
{
|
|
frequency &= 0x00FF;
|
|
frequency |= (value & 0x00FF) << 8;
|
|
}
|
|
}
|
|
|
|
public int Oscillator
|
|
{
|
|
get
|
|
{
|
|
return output;
|
|
}
|
|
}
|
|
|
|
public int Output(Voice ringModSource)
|
|
{
|
|
|
|
{
|
|
if (waveform != 0)
|
|
{
|
|
waveformIndex = (accumulator ^ (ringModSource.accumulator & ringMsbMask)) >> 12;
|
|
output = wave[waveformIndex] & (noPulse | pulse) & noNoiseOrNoise;
|
|
if (waveform > 8)
|
|
WriteShiftReg();
|
|
}
|
|
else
|
|
{
|
|
if (floatOutputTTL != 0 && --floatOutputTTL == 0)
|
|
output = 0x000;
|
|
}
|
|
pulse = ((accumulator >> 12) >= pulseWidth) ? 0xFFF : 0x000;
|
|
return output;
|
|
}
|
|
}
|
|
|
|
public int PulseWidth
|
|
{
|
|
get
|
|
{
|
|
return pulseWidth;
|
|
}
|
|
set
|
|
{
|
|
pulseWidth = value;
|
|
}
|
|
}
|
|
|
|
public int PulseWidthLo
|
|
{
|
|
get
|
|
{
|
|
return (pulseWidth & 0xFF);
|
|
}
|
|
set
|
|
{
|
|
pulseWidth &= 0x0F00;
|
|
pulseWidth |= value & 0x00FF;
|
|
}
|
|
}
|
|
|
|
public int PulseWidthHi
|
|
{
|
|
get
|
|
{
|
|
return (pulseWidth >> 8);
|
|
}
|
|
set
|
|
{
|
|
pulseWidth &= 0x00FF;
|
|
pulseWidth |= (value & 0x000F) << 8;
|
|
}
|
|
}
|
|
|
|
public bool RingMod
|
|
{
|
|
get
|
|
{
|
|
return ringMod;
|
|
}
|
|
}
|
|
|
|
public bool Sync
|
|
{
|
|
get
|
|
{
|
|
return sync;
|
|
}
|
|
}
|
|
|
|
public void Synchronize(Voice target, Voice source)
|
|
{
|
|
if (msbRising && target.sync && !(sync && source.msbRising))
|
|
target.accumulator = 0;
|
|
}
|
|
|
|
public bool Test
|
|
{
|
|
get
|
|
{
|
|
return test;
|
|
}
|
|
}
|
|
|
|
public int Waveform
|
|
{
|
|
get
|
|
{
|
|
return waveform;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
|
|
public void SyncState(Serializer ser)
|
|
{
|
|
SaveState.SyncObject(ser, this);
|
|
|
|
if (ser.IsReader)
|
|
wave = waveTable[waveform];
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|