commodore64: added SID waveform generators (no sound output yet)

This commit is contained in:
saxxonpike 2012-11-08 00:09:20 +00:00
parent 835084d812
commit ee27ce7828
2 changed files with 190 additions and 11 deletions

View File

@ -5,6 +5,14 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum SidEnvelopeState
{
Disabled,
Attack,
Decay,
Release
}
public enum SidMode
{
Sid6581,
@ -17,7 +25,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool BP;
public bool D3;
public int[] DCY = new int[3];
public int ENV3;
public int[] ENV = new int[3];
public int[] F = new int[3];
public int FC;
public bool[] FILT = new bool[3];
@ -26,7 +34,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool HP;
public bool LP;
public bool[] NOISE = new bool[3];
public int OSC3;
public int[] OSC = new int[3];
public int POTX;
public int POTY;
public int[] PW = new int[3];
@ -34,6 +42,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int[] RLS = new int[3];
public bool[] RMOD = new bool[3];
public bool[] SAW = new bool[3];
public int[] SR = new int[3];
public bool[] SQU = new bool[3];
public int[] STN = new int[3];
public bool[] SYNC = new bool[3];
@ -44,6 +53,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
public SidRegs()
{
// power on state
SR[0] = 0x7FFFFF;
SR[1] = 0x7FFFFF;
SR[2] = 0x7FFFFF;
}
public byte this[int addr]
@ -131,10 +143,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
result = POTY;
break;
case 0x1B:
result = OSC3;
result = OSC[2] >> 4;
break;
case 0x1C:
result = ENV3;
result = ENV[2];
break;
default:
result = 0;
@ -234,10 +246,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
POTY = val;
break;
case 0x1B:
OSC3 = val;
OSC[2] = val << 4;
break;
case 0x1C:
ENV3 = val;
ENV[2] = val;
break;
}
}
@ -247,12 +259,28 @@ namespace BizHawk.Emulation.Computers.Commodore64
public class Sid
{
private int[] envRateIndex = {
9, 32, 63, 95,
149, 220, 267, 313,
392, 977, 1954, 3126,
3907, 11720, 19532, 31251
};
private int[] syncIndex = { 2, 0, 1 };
public Func<int> ReadPotX;
public Func<int> ReadPotY;
public int clock;
public bool[] envEnable = new bool[3];
public int[] envExpCounter = new int[3];
public int[] envRate = new int[3];
public int[] envRateCounter = new int[3];
public SidEnvelopeState[] envState = new SidEnvelopeState[3];
public bool[] gateLastCycle = new bool[3];
public int output;
public int potCycle;
public SidRegs regs;
public int[] waveClock = new int[3];
public Sid()
{
@ -273,13 +301,144 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void PerformCycle()
{
output = 0;
if (potCycle == 0)
// accumulator is 24 bits
clock = (clock + 1) & 0xFFFFFF;
ProcessVoice(0);
ProcessVoice(1);
ProcessVoice(2);
// query pots every 512 cycles
if ((clock & 0x1FF) == 0x000)
{
regs.POTX = ReadPotX() & 0xFF;
regs.POTY = ReadPotY() & 0xFF;
}
potCycle = (potCycle + 1) & 0x1FF;
}
private void ProcessEnvelope(int index)
{
// envelope counter is 15 bits
envRateCounter[index] &= 0x7FFF;
if (!gateLastCycle[index] && regs.GATE[index])
{
envState[index] = SidEnvelopeState.Attack;
envEnable[index] = true;
}
else if (gateLastCycle[index] && !regs.GATE[index])
{
envState[index] = SidEnvelopeState.Release;
}
if (envRateCounter[index] == envRate[index])
{
envExpCounter[index] = 0;
if (envEnable[index])
{
}
}
gateLastCycle[index] = regs.GATE[index];
}
private void ProcessShiftRegister(int index)
{
int newBit = ((regs.SR[index] >> 22) ^ (regs.SR[index] >> 17)) & 0x1;
regs.SR[index] = ((regs.SR[index] << 1) | newBit) & 0x7FFFFF;
}
private void ProcessVoice(int index)
{
int triOutput;
int sawOutput;
int squOutput;
int noiseOutput;
int finalOutput = 0xFFFFFF;
bool outputEnabled = false;
// triangle waveform
if (regs.TRI[index])
{
triOutput = waveClock[index] >> 12;
if (regs.SYNC[index])
triOutput ^= regs.OSC[syncIndex[index]] & 0x800;
if ((triOutput & 0x800) != 0x000)
triOutput &= 0xFFF;
triOutput <<= 1;
finalOutput &= triOutput;
outputEnabled = true;
}
// saw waveform
if (regs.SAW[index])
{
sawOutput = waveClock[index] >> 12;
finalOutput &= sawOutput;
outputEnabled = true;
}
// square waveform
if (regs.SQU[index])
{
if (regs.TEST[index])
{
squOutput = 0xFFF;
}
else
{
if (regs.PW[index] >= (waveClock[index] >> 12))
squOutput = 0xFFF;
else
squOutput = 0x000;
}
finalOutput &= squOutput;
outputEnabled = true;
}
// noise waveform
if (regs.NOISE[index])
{
int sr = regs.SR[index];
noiseOutput = sr & 0x100000 >> 9;
noiseOutput |= sr & 0x040000 >> 8;
noiseOutput |= sr & 0x004000 >> 5;
noiseOutput |= sr & 0x000800 >> 3;
noiseOutput |= sr & 0x000200 >> 2;
noiseOutput |= sr & 0x000020 << 1;
noiseOutput |= sr & 0x000004 << 3;
noiseOutput |= sr & 0x000001 << 4;
finalOutput &= noiseOutput;
outputEnabled = true;
}
// test bit resets the oscillator and silences output
if (regs.TEST[index])
{
waveClock[index] = 0x000000;
outputEnabled = false;
}
else
{
// shift register for generating noise
if ((waveClock[index] & 0x7FFFF) == 0x00000)
ProcessShiftRegister(index);
// increment wave clock
waveClock[index] = (waveClock[index] + regs.F[index]) & 0xFFFFFF;
}
// process the envelope generator
//ProcessEnvelope(index);
// write to internal reg
if (outputEnabled)
regs.OSC[index] = finalOutput;
else
regs.OSC[index] = 0x000000;
}
public byte Read(ushort addr)
@ -298,6 +457,22 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
}
private void UpdateEnvelopeRateCounter(int index)
{
switch (envState[index])
{
case SidEnvelopeState.Attack:
envRate[index] = envRateIndex[regs.ATK[index]];
break;
case SidEnvelopeState.Decay:
envRate[index] = envRateIndex[regs.DCY[index]];
break;
case SidEnvelopeState.Release:
envRate[index] = envRateIndex[regs.RLS[index]];
break;
}
}
public void Write(ushort addr, byte val)
{
addr &= 0x1F;

View File

@ -827,7 +827,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
if (!idle && cycle >= 16 && cycle < 56)
{
// todo: implement XSCROLL properly
if (regs.XSCROLL == (rasterOffsetX & 0x7))
// comparing to (rasterOffsetX & 0x7) seems to align
// properly but smooth scrolling is not possible
// comparing to i works but then the screen
// is not aligned anymore...
if (regs.XSCROLL == i)
{
characterColumn = 0;
characterData = characterMemory[regs.VMLI];