commodore64: VIC sprite renderer fixed (shows line 21), SID noise shift register fixed (proper output frequency)
This commit is contained in:
parent
607998ddd9
commit
30d18601ba
|
@ -93,6 +93,8 @@
|
|||
<Compile Include="Computers\Commodore64\Sid.cs" />
|
||||
<Compile Include="Computers\Commodore64\SidSoundProvider.cs" />
|
||||
<Compile Include="Computers\Commodore64\VicII.cs" />
|
||||
<Compile Include="Computers\Commodore64\VicIIBackgroundGenerator.cs" />
|
||||
<Compile Include="Computers\Commodore64\VicIISpriteGenerator.cs" />
|
||||
<Compile Include="Computers\Commodore64\VicIIVideoProvider.cs" />
|
||||
<Compile Include="Consoles\Atari\2600\Atari2600.cs" />
|
||||
<Compile Include="Consoles\Atari\2600\Atari2600.Core.cs" />
|
||||
|
|
|
@ -18,43 +18,53 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
Sid8580
|
||||
}
|
||||
|
||||
public class VoiceRegs
|
||||
{
|
||||
public int ATK;
|
||||
public int DCY;
|
||||
public int ENV;
|
||||
public int F;
|
||||
public bool FILT;
|
||||
public bool GATE;
|
||||
public bool NOISE;
|
||||
public int OSC;
|
||||
public int PW;
|
||||
public int RLS;
|
||||
public bool RMOD;
|
||||
public bool SAW;
|
||||
public int SR;
|
||||
public bool SQU;
|
||||
public int STN;
|
||||
public bool SYNC;
|
||||
public bool TEST;
|
||||
public bool TRI;
|
||||
}
|
||||
|
||||
public class SidRegs
|
||||
{
|
||||
public int[] ATK = new int[3];
|
||||
public bool BP;
|
||||
public bool D3;
|
||||
public int[] DCY = new int[3];
|
||||
public int[] ENV = new int[3];
|
||||
public int[] F = new int[3];
|
||||
public int FC;
|
||||
public bool[] FILT = new bool[3];
|
||||
public bool FILTEX;
|
||||
public bool[] GATE = new bool[3];
|
||||
public bool HP;
|
||||
public bool LP;
|
||||
public bool[] NOISE = new bool[3];
|
||||
public int[] OSC = new int[3];
|
||||
public int POTX;
|
||||
public int POTY;
|
||||
public int[] PW = new int[3];
|
||||
public int RES;
|
||||
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];
|
||||
public bool[] TEST = new bool[3];
|
||||
public bool[] TRI = new bool[3];
|
||||
public int VOL;
|
||||
|
||||
public VoiceRegs[] Voices;
|
||||
|
||||
public SidRegs()
|
||||
{
|
||||
Voices = new VoiceRegs[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
Voices[i] = new VoiceRegs();
|
||||
|
||||
// power on state
|
||||
SR[0] = 0x7FFFFF;
|
||||
SR[1] = 0x7FFFFF;
|
||||
SR[2] = 0x7FFFFF;
|
||||
Voices[0].SR = 0x7FFFFF;
|
||||
Voices[1].SR = 0x7FFFFF;
|
||||
Voices[2].SR = 0x7FFFFF;
|
||||
}
|
||||
|
||||
public byte this[int addr]
|
||||
|
@ -71,49 +81,49 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x00:
|
||||
case 0x07:
|
||||
case 0x0E:
|
||||
result = F[addr / 7] & 0xFF;
|
||||
result = Voices[addr / 7].F & 0xFF;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x08:
|
||||
case 0x0F:
|
||||
result = (F[addr / 7] & 0xFF00) >> 8;
|
||||
result = (Voices[addr / 7].F & 0xFF00) >> 8;
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x09:
|
||||
case 0x10:
|
||||
result = PW[addr / 7] & 0xFF;
|
||||
result = Voices[addr / 7].PW & 0xFF;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x0A:
|
||||
case 0x11:
|
||||
result = (PW[addr / 7] & 0x0F00) >> 8;
|
||||
result = (Voices[addr / 7].PW & 0x0F00) >> 8;
|
||||
break;
|
||||
case 0x04:
|
||||
case 0x0B:
|
||||
case 0x12:
|
||||
index = addr / 7;
|
||||
result = GATE[index] ? 0x01 : 0x00;
|
||||
result |= SYNC[index] ? 0x02 : 0x00;
|
||||
result |= RMOD[index] ? 0x04 : 0x00;
|
||||
result |= TEST[index] ? 0x08 : 0x00;
|
||||
result |= TRI[index] ? 0x10 : 0x00;
|
||||
result |= SAW[index] ? 0x20 : 0x00;
|
||||
result |= SQU[index] ? 0x40 : 0x00;
|
||||
result |= NOISE[index] ? 0x80 : 0x00;
|
||||
result = Voices[index].GATE ? 0x01 : 0x00;
|
||||
result |= Voices[index].SYNC ? 0x02 : 0x00;
|
||||
result |= Voices[index].RMOD ? 0x04 : 0x00;
|
||||
result |= Voices[index].TEST ? 0x08 : 0x00;
|
||||
result |= Voices[index].TRI ? 0x10 : 0x00;
|
||||
result |= Voices[index].SAW ? 0x20 : 0x00;
|
||||
result |= Voices[index].SQU ? 0x40 : 0x00;
|
||||
result |= Voices[index].NOISE ? 0x80 : 0x00;
|
||||
break;
|
||||
case 0x05:
|
||||
case 0x0C:
|
||||
case 0x13:
|
||||
index = addr / 7;
|
||||
result = (ATK[index] & 0xF) << 4;
|
||||
result |= DCY[index] & 0xF;
|
||||
result = (Voices[index].ATK & 0xF) << 4;
|
||||
result |= Voices[index].DCY & 0xF;
|
||||
break;
|
||||
case 0x06:
|
||||
case 0x0D:
|
||||
case 0x14:
|
||||
index = addr / 7;
|
||||
result = (STN[index] & 0xF) << 4;
|
||||
result |= RLS[index] & 0xF;
|
||||
result = (Voices[index].STN & 0xF) << 4;
|
||||
result |= Voices[index].RLS & 0xF;
|
||||
break;
|
||||
case 0x15:
|
||||
result = FC & 0x7;
|
||||
|
@ -122,9 +132,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
result = (FC & 0x7F8) >> 3;
|
||||
break;
|
||||
case 0x17:
|
||||
result = FILT[0] ? 0x01 : 0x00;
|
||||
result |= FILT[1] ? 0x02 : 0x00;
|
||||
result |= FILT[2] ? 0x04 : 0x00;
|
||||
result = Voices[0].FILT ? 0x01 : 0x00;
|
||||
result |= Voices[1].FILT ? 0x02 : 0x00;
|
||||
result |= Voices[2].FILT ? 0x04 : 0x00;
|
||||
result |= FILTEX ? 0x08 : 0x00;
|
||||
result |= (RES & 0xF) << 4;
|
||||
break;
|
||||
|
@ -142,10 +152,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
result = POTY;
|
||||
break;
|
||||
case 0x1B:
|
||||
result = OSC[2] >> 4;
|
||||
result = Voices[2].OSC >> 4;
|
||||
break;
|
||||
case 0x1C:
|
||||
result = ENV[2];
|
||||
result = Voices[2].ENV;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
|
@ -165,56 +175,56 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x07:
|
||||
case 0x0E:
|
||||
index = addr / 7;
|
||||
F[index] &= 0xFF00;
|
||||
F[index] |= val;
|
||||
Voices[index].F &= 0xFF00;
|
||||
Voices[index].F |= val;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x08:
|
||||
case 0x0F:
|
||||
index = addr / 7;
|
||||
F[index] &= 0xFF;
|
||||
F[index] |= val << 8;
|
||||
Voices[index].F &= 0xFF;
|
||||
Voices[index].F |= val << 8;
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x09:
|
||||
case 0x10:
|
||||
index = addr / 7;
|
||||
PW[index] &= 0x0F00;
|
||||
PW[index] |= val;
|
||||
Voices[index].PW &= 0x0F00;
|
||||
Voices[index].PW |= val;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x0A:
|
||||
case 0x11:
|
||||
index = addr / 7;
|
||||
PW[index] &= 0xFF;
|
||||
PW[index] |= (val & 0x0F) << 8;
|
||||
Voices[index].PW &= 0xFF;
|
||||
Voices[index].PW |= (val & 0x0F) << 8;
|
||||
break;
|
||||
case 0x04:
|
||||
case 0x0B:
|
||||
case 0x12:
|
||||
index = addr / 7;
|
||||
GATE[index] = ((val & 0x01) != 0x00);
|
||||
SYNC[index] = ((val & 0x02) != 0x00);
|
||||
RMOD[index] = ((val & 0x04) != 0x00);
|
||||
TEST[index] = ((val & 0x08) != 0x00);
|
||||
TRI[index] = ((val & 0x10) != 0x00);
|
||||
SAW[index] = ((val & 0x20) != 0x00);
|
||||
SQU[index] = ((val & 0x40) != 0x00);
|
||||
NOISE[index] = ((val & 0x80) != 0x00);
|
||||
Voices[index].GATE = ((val & 0x01) != 0x00);
|
||||
Voices[index].SYNC = ((val & 0x02) != 0x00);
|
||||
Voices[index].RMOD = ((val & 0x04) != 0x00);
|
||||
Voices[index].TEST = ((val & 0x08) != 0x00);
|
||||
Voices[index].TRI = ((val & 0x10) != 0x00);
|
||||
Voices[index].SAW = ((val & 0x20) != 0x00);
|
||||
Voices[index].SQU = ((val & 0x40) != 0x00);
|
||||
Voices[index].NOISE = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x05:
|
||||
case 0x0C:
|
||||
case 0x13:
|
||||
index = addr / 7;
|
||||
ATK[index] = (val >> 4) & 0xF;
|
||||
DCY[index] = val & 0xF;
|
||||
Voices[index].ATK = (val >> 4) & 0xF;
|
||||
Voices[index].DCY = val & 0xF;
|
||||
break;
|
||||
case 0x06:
|
||||
case 0x0D:
|
||||
case 0x14:
|
||||
index = addr / 7;
|
||||
STN[index] = (val >> 4) & 0xF;
|
||||
RLS[index] = val & 0xF;
|
||||
Voices[index].STN = (val >> 4) & 0xF;
|
||||
Voices[index].RLS = val & 0xF;
|
||||
break;
|
||||
case 0x15:
|
||||
FC &= 0x7F8;
|
||||
|
@ -225,9 +235,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
FC |= val << 3;
|
||||
break;
|
||||
case 0x17:
|
||||
FILT[0] = ((val & 0x01) != 0x00);
|
||||
FILT[1] = ((val & 0x02) != 0x00);
|
||||
FILT[2] = ((val & 0x04) != 0x00);
|
||||
Voices[0].FILT = ((val & 0x01) != 0x00);
|
||||
Voices[1].FILT = ((val & 0x02) != 0x00);
|
||||
Voices[2].FILT = ((val & 0x04) != 0x00);
|
||||
FILTEX = ((val & 0x08) != 0x00);
|
||||
RES = (val >> 4);
|
||||
break;
|
||||
|
@ -245,10 +255,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
POTY = val;
|
||||
break;
|
||||
case 0x1B:
|
||||
OSC[2] = val << 4;
|
||||
Voices[2].OSC = val << 4;
|
||||
break;
|
||||
case 0x1C:
|
||||
ENV[2] = val;
|
||||
Voices[2].ENV = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -266,6 +276,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
};
|
||||
|
||||
private int[] syncIndex = { 2, 0, 1 };
|
||||
private VoiceRegs[] voices;
|
||||
|
||||
public Func<int> ReadPotX;
|
||||
public Func<int> ReadPotY;
|
||||
|
@ -307,6 +318,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public void HardReset()
|
||||
{
|
||||
regs = new SidRegs();
|
||||
voices = regs.Voices;
|
||||
}
|
||||
|
||||
private short Mix(int input, short mixSource)
|
||||
|
@ -330,11 +342,24 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
// accumulator is 24 bits
|
||||
clock = (clock + 1) & 0xFFFFFF;
|
||||
ProcessAccumulator(0);
|
||||
ProcessAccumulator(1);
|
||||
ProcessAccumulator(2);
|
||||
|
||||
// process each voice
|
||||
ProcessVoice(0);
|
||||
ProcessVoice(1);
|
||||
ProcessVoice(2);
|
||||
|
||||
// process voices again for best hard sync
|
||||
if (voices[1].SYNC)
|
||||
ProcessVoice(0);
|
||||
if (voices[2].SYNC)
|
||||
ProcessVoice(1);
|
||||
if (voices[0].SYNC)
|
||||
ProcessVoice(2);
|
||||
|
||||
// submit sample to soundprovider
|
||||
SubmitSample();
|
||||
|
||||
// query pots every 512 cycles
|
||||
|
@ -350,17 +375,38 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
regs[addr & 0x1F] = val;
|
||||
}
|
||||
|
||||
private void ProcessAccumulator(int index)
|
||||
{
|
||||
// test bit resets the oscillator
|
||||
if (voices[index].TEST)
|
||||
{
|
||||
waveClock[index] = 0x000000;
|
||||
voices[index].SR = 0x7FFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastWaveClock = waveClock[index];
|
||||
|
||||
// increment wave clock
|
||||
waveClock[index] = (waveClock[index] + voices[index].F) & 0x00FFFFFF;
|
||||
|
||||
// process shift register if needed
|
||||
if ((lastWaveClock & 0x100000) != (waveClock[index] & 0x100000))
|
||||
ProcessShiftRegister(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessEnvelope(int index)
|
||||
{
|
||||
// envelope counter is 15 bits
|
||||
envRateCounter[index] &= 0x7FFF;
|
||||
|
||||
if (!gateLastCycle[index] && regs.GATE[index])
|
||||
if (!gateLastCycle[index] && voices[index].GATE)
|
||||
{
|
||||
envState[index] = SidEnvelopeState.Attack;
|
||||
envEnable[index] = true;
|
||||
}
|
||||
else if (gateLastCycle[index] && !regs.GATE[index])
|
||||
else if (gateLastCycle[index] && !voices[index].GATE)
|
||||
{
|
||||
envState[index] = SidEnvelopeState.Release;
|
||||
}
|
||||
|
@ -374,13 +420,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
}
|
||||
|
||||
gateLastCycle[index] = regs.GATE[index];
|
||||
gateLastCycle[index] = voices[index].GATE;
|
||||
}
|
||||
|
||||
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;
|
||||
int newBit = ((voices[index].SR >> 22) ^ (voices[index].SR >> 17)) & 0x1;
|
||||
voices[index].SR = ((voices[index].SR << 1) | newBit) & 0x7FFFFF;
|
||||
}
|
||||
|
||||
private void ProcessVoice(int index)
|
||||
|
@ -393,11 +439,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
bool outputEnabled = false;
|
||||
|
||||
// triangle waveform
|
||||
if (regs.TRI[index])
|
||||
if (voices[index].TRI)
|
||||
{
|
||||
triOutput = (waveClock[index] >> 12) & 0xFFF;
|
||||
if (regs.SYNC[index])
|
||||
triOutput ^= regs.OSC[syncIndex[index]] & 0x800;
|
||||
if (voices[index].SYNC)
|
||||
triOutput ^= voices[syncIndex[index]].OSC & 0x800;
|
||||
|
||||
if ((triOutput & 0x800) != 0x000)
|
||||
triOutput ^= 0x7FF;
|
||||
|
@ -409,7 +455,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
|
||||
// saw waveform
|
||||
if (regs.SAW[index])
|
||||
if (voices[index].SAW)
|
||||
{
|
||||
sawOutput = (waveClock[index] >> 12) & 0xFFF;
|
||||
finalOutput &= sawOutput;
|
||||
|
@ -417,25 +463,25 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
|
||||
// square waveform
|
||||
if (regs.SQU[index])
|
||||
if (voices[index].SQU)
|
||||
{
|
||||
if (regs.TEST[index])
|
||||
if (voices[index].TEST)
|
||||
{
|
||||
squOutput = 0xFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
squOutput = (waveClock[index] >> 12) >= regs.PW[index] ? 0xFFF : 0x000;
|
||||
squOutput = (waveClock[index] >> 12) >= voices[index].PW ? 0xFFF : 0x000;
|
||||
}
|
||||
finalOutput &= squOutput;
|
||||
outputEnabled = true;
|
||||
}
|
||||
|
||||
// noise waveform
|
||||
if (regs.NOISE[index])
|
||||
if (voices[index].NOISE)
|
||||
{
|
||||
// shift register information is from reSID
|
||||
int sr = regs.SR[index];
|
||||
int sr = voices[index].SR;
|
||||
noiseOutput = sr & 0x100000 >> 9;
|
||||
noiseOutput |= sr & 0x040000 >> 8;
|
||||
noiseOutput |= sr & 0x004000 >> 5;
|
||||
|
@ -448,35 +494,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
outputEnabled = true;
|
||||
}
|
||||
|
||||
// test bit resets the oscillator and silences output
|
||||
if (regs.TEST[index])
|
||||
{
|
||||
waveClock[index] = 0x000000;
|
||||
outputEnabled = false;
|
||||
regs.SR[index] = 0x7FFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
// shift register for generating noise
|
||||
if ((waveClock[index] & 0x100000) != 0)
|
||||
ProcessShiftRegister(index);
|
||||
|
||||
// increment wave clock
|
||||
waveClock[index] = (waveClock[index] + regs.F[index]) & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
// process the envelope generator
|
||||
//ProcessEnvelope(index);
|
||||
|
||||
// a little hack until we fix the envelope generator
|
||||
outputEnabled = regs.GATE[index];
|
||||
|
||||
outputEnabled = voices[index].GATE;
|
||||
|
||||
// write to internal reg
|
||||
if (outputEnabled)
|
||||
regs.OSC[index] = finalOutput;
|
||||
voices[index].OSC = finalOutput;
|
||||
else
|
||||
regs.OSC[index] = 0x000;
|
||||
voices[index].OSC = 0x000;
|
||||
}
|
||||
|
||||
public byte Read(ushort addr)
|
||||
|
@ -500,13 +528,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
switch (envState[index])
|
||||
{
|
||||
case SidEnvelopeState.Attack:
|
||||
envRate[index] = envRateIndex[regs.ATK[index]];
|
||||
envRate[index] = envRateIndex[voices[index].ATK];
|
||||
break;
|
||||
case SidEnvelopeState.Decay:
|
||||
envRate[index] = envRateIndex[regs.DCY[index]];
|
||||
envRate[index] = envRateIndex[voices[index].DCY];
|
||||
break;
|
||||
case SidEnvelopeState.Release:
|
||||
envRate[index] = envRateIndex[regs.RLS[index]];
|
||||
envRate[index] = envRateIndex[voices[index].RLS];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +558,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
private void WriteShiftRegister(int index, int sample)
|
||||
{
|
||||
regs.SR[index] &=
|
||||
voices[index].SR &=
|
||||
~((1 << 20) | (1 << 18) | (1 << 14) | (1 << 11) | (1 << 9) | (1 << 5) | (1 << 2) | (1 << 0)) |
|
||||
((sample & 0x800) << 9) |
|
||||
((sample & 0x400) << 8) |
|
||||
|
|
|
@ -64,13 +64,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
if (sampleCounter == 0)
|
||||
{
|
||||
short output;
|
||||
output = Mix(regs.OSC[0], 0);
|
||||
output = Mix(regs.OSC[1], output);
|
||||
output = Mix(voices[0].OSC, 0);
|
||||
output = Mix(voices[1].OSC, output);
|
||||
|
||||
// voice 3 can be disabled with a specific register, but
|
||||
// when the filter is enabled, it still plays
|
||||
if (!regs.D3 || regs.FILT[2])
|
||||
output = Mix(regs.OSC[2], output);
|
||||
if (!regs.D3 || voices[2].FILT)
|
||||
output = Mix(voices[2].OSC, output);
|
||||
|
||||
// run twice since the buffer expects stereo sound (I THINK)
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
|
|
@ -5,6 +5,31 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Emulation.Computers.Commodore64
|
||||
{
|
||||
public class SpriteRegs
|
||||
{
|
||||
public int MC; // (internal)
|
||||
public int MCBASE; // (internal)
|
||||
public bool MD; // (internal)
|
||||
public bool MDMA; // (internal)
|
||||
public int MPTR; // (internal)
|
||||
public Int32 MSR; // (internal)
|
||||
public bool MSRA; // (internal)
|
||||
public int MSRC; // (internal)
|
||||
public int MxC; // sprite color
|
||||
public bool MxD; // sprite-data collision
|
||||
public bool MxDP; // sprite priority
|
||||
public bool MxE; // sprite enabled
|
||||
public bool MxM; // sprite-sprite collision
|
||||
public bool MxMC; // sprite multicolor
|
||||
public int MxX; // sprite X coordinate
|
||||
public bool MxXE; // sprite X expansion
|
||||
public bool MxXEToggle; // (internal)
|
||||
public int MxXLatch; // (internal)
|
||||
public int MxY; // sprite Y coordinate
|
||||
public bool MxYE; // sprite Y expansion
|
||||
public bool MxYEToggle; // (internal)
|
||||
}
|
||||
|
||||
public class VicIIRegs
|
||||
{
|
||||
public bool BMM; // bitmap mode
|
||||
|
@ -25,29 +50,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public bool IRST; // raster line interrupt active
|
||||
public int LPX; // lightpen X coordinate
|
||||
public int LPY; // lightpen Y coordinate
|
||||
public int[] MC = new int[8]; // (internal)
|
||||
public int[] MCBASE = new int[8]; // (internal)
|
||||
public bool MCM; // multicolor mode
|
||||
public bool[] MD = new bool[8]; // (internal)
|
||||
public bool[] MDMA = new bool[8]; // (internal)
|
||||
public int[] MMx = new int[2]; // sprite extra color
|
||||
public int[] MPTR = new int[8]; // (internal)
|
||||
public Int32[] MSR = new Int32[8]; // (internal)
|
||||
public bool[] MSRA = new bool[8]; // (internal)
|
||||
public int[] MSRC = new int[8]; // (internal)
|
||||
public int[] MxC = new int[8]; // sprite color
|
||||
public bool[] MxD = new bool[8]; // sprite-data collision
|
||||
public bool[] MxDP = new bool[8]; // sprite priority
|
||||
public bool[] MxE = new bool[8]; // sprite enabled
|
||||
public bool[] MxM = new bool[8]; // sprite-sprite collision
|
||||
public bool[] MxMC = new bool[8]; // sprite multicolor
|
||||
public int[] MxX = new int[8]; // sprite X coordinate
|
||||
public bool[] MxXE = new bool[8]; // sprite X expansion
|
||||
public bool[] MxXEToggle = new bool[8]; // (internal)
|
||||
public int[] MxXLatch = new int[8]; // (internal)
|
||||
public int[] MxY = new int[8]; // sprite Y coordinate
|
||||
public bool[] MxYE = new bool[8]; // sprite Y expansion
|
||||
public bool[] MxYEToggle = new bool[8]; // (internal)
|
||||
public int RASTER; // current raster line
|
||||
public int RC; // (internal)
|
||||
public bool RES; // reset bit (does nothing in this version of the VIC)
|
||||
|
@ -59,6 +63,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public int XSCROLL; // X scroll position
|
||||
public int YSCROLL; // Y scroll position
|
||||
|
||||
public SpriteRegs[] Sprites = new SpriteRegs[8];
|
||||
|
||||
public VicIIRegs()
|
||||
{
|
||||
// power on state
|
||||
|
@ -67,6 +73,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
this[0x18] = 0x01;
|
||||
this[0x19] = 0x71;
|
||||
this[0x1A] = 0xF0;
|
||||
|
||||
// init sprites
|
||||
for (int i = 0; i < 8; i++)
|
||||
Sprites[i] = new SpriteRegs();
|
||||
}
|
||||
|
||||
public byte this[int addr]
|
||||
|
@ -86,7 +96,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x0A:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
result = MxX[addr >> 1];
|
||||
result = Sprites[addr >> 1].MxX;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x03:
|
||||
|
@ -96,17 +106,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x0B:
|
||||
case 0x0D:
|
||||
case 0x0F:
|
||||
result = MxY[addr >> 1];
|
||||
result = Sprites[addr >> 1].MxY;
|
||||
break;
|
||||
case 0x10:
|
||||
result = ((MxX[0] & 0x100) != 0) ? 0x01 : 0x00;
|
||||
result |= ((MxX[1] & 0x100) != 0) ? 0x02 : 0x00;
|
||||
result |= ((MxX[2] & 0x100) != 0) ? 0x04 : 0x00;
|
||||
result |= ((MxX[3] & 0x100) != 0) ? 0x08 : 0x00;
|
||||
result |= ((MxX[4] & 0x100) != 0) ? 0x10 : 0x00;
|
||||
result |= ((MxX[5] & 0x100) != 0) ? 0x20 : 0x00;
|
||||
result |= ((MxX[6] & 0x100) != 0) ? 0x40 : 0x00;
|
||||
result |= ((MxX[7] & 0x100) != 0) ? 0x80 : 0x00;
|
||||
result = ((Sprites[0].MxX & 0x100) != 0) ? 0x01 : 0x00;
|
||||
result |= ((Sprites[1].MxX & 0x100) != 0) ? 0x02 : 0x00;
|
||||
result |= ((Sprites[2].MxX & 0x100) != 0) ? 0x04 : 0x00;
|
||||
result |= ((Sprites[3].MxX & 0x100) != 0) ? 0x08 : 0x00;
|
||||
result |= ((Sprites[4].MxX & 0x100) != 0) ? 0x10 : 0x00;
|
||||
result |= ((Sprites[5].MxX & 0x100) != 0) ? 0x20 : 0x00;
|
||||
result |= ((Sprites[6].MxX & 0x100) != 0) ? 0x40 : 0x00;
|
||||
result |= ((Sprites[7].MxX & 0x100) != 0) ? 0x80 : 0x00;
|
||||
break;
|
||||
case 0x11:
|
||||
result = YSCROLL & 0x07;
|
||||
|
@ -126,14 +136,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
result = LPY;
|
||||
break;
|
||||
case 0x15:
|
||||
result = (MxE[0] ? 0x01 : 0x00);
|
||||
result |= (MxE[1] ? 0x02 : 0x00);
|
||||
result |= (MxE[2] ? 0x04 : 0x00);
|
||||
result |= (MxE[3] ? 0x08 : 0x00);
|
||||
result |= (MxE[4] ? 0x10 : 0x00);
|
||||
result |= (MxE[5] ? 0x20 : 0x00);
|
||||
result |= (MxE[6] ? 0x40 : 0x00);
|
||||
result |= (MxE[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxE ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxE ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxE ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxE ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxE ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxE ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxE ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxE ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x16:
|
||||
result &= 0xC0;
|
||||
|
@ -143,14 +153,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
result |= (RES ? 0x20 : 0x00);
|
||||
break;
|
||||
case 0x17:
|
||||
result = (MxYE[0] ? 0x01 : 0x00);
|
||||
result |= (MxYE[1] ? 0x02 : 0x00);
|
||||
result |= (MxYE[2] ? 0x04 : 0x00);
|
||||
result |= (MxYE[3] ? 0x08 : 0x00);
|
||||
result |= (MxYE[4] ? 0x10 : 0x00);
|
||||
result |= (MxYE[5] ? 0x20 : 0x00);
|
||||
result |= (MxYE[6] ? 0x40 : 0x00);
|
||||
result |= (MxYE[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxYE ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxYE ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxYE ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxYE ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxYE ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxYE ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxYE ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxYE ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x18:
|
||||
result &= 0x01;
|
||||
|
@ -173,54 +183,54 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
result |= (ELP ? 0x08 : 0x00);
|
||||
break;
|
||||
case 0x1B:
|
||||
result = (MxDP[0] ? 0x01 : 0x00);
|
||||
result |= (MxDP[1] ? 0x02 : 0x00);
|
||||
result |= (MxDP[2] ? 0x04 : 0x00);
|
||||
result |= (MxDP[3] ? 0x08 : 0x00);
|
||||
result |= (MxDP[4] ? 0x10 : 0x00);
|
||||
result |= (MxDP[5] ? 0x20 : 0x00);
|
||||
result |= (MxDP[6] ? 0x40 : 0x00);
|
||||
result |= (MxDP[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxDP ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxDP ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxDP ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxDP ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxDP ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxDP ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxDP ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxDP ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x1C:
|
||||
result = (MxMC[0] ? 0x01 : 0x00);
|
||||
result |= (MxMC[1] ? 0x02 : 0x00);
|
||||
result |= (MxMC[2] ? 0x04 : 0x00);
|
||||
result |= (MxMC[3] ? 0x08 : 0x00);
|
||||
result |= (MxMC[4] ? 0x10 : 0x00);
|
||||
result |= (MxMC[5] ? 0x20 : 0x00);
|
||||
result |= (MxMC[6] ? 0x40 : 0x00);
|
||||
result |= (MxMC[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxMC ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxMC ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxMC ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxMC ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxMC ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxMC ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxMC ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxMC ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x1D:
|
||||
result = (MxXE[0] ? 0x01 : 0x00);
|
||||
result |= (MxXE[1] ? 0x02 : 0x00);
|
||||
result |= (MxXE[2] ? 0x04 : 0x00);
|
||||
result |= (MxXE[3] ? 0x08 : 0x00);
|
||||
result |= (MxXE[4] ? 0x10 : 0x00);
|
||||
result |= (MxXE[5] ? 0x20 : 0x00);
|
||||
result |= (MxXE[6] ? 0x40 : 0x00);
|
||||
result |= (MxXE[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxXE ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxXE ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxXE ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxXE ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxXE ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxXE ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxXE ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxXE ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x1E:
|
||||
result = (MxM[0] ? 0x01 : 0x00);
|
||||
result |= (MxM[1] ? 0x02 : 0x00);
|
||||
result |= (MxM[2] ? 0x04 : 0x00);
|
||||
result |= (MxM[3] ? 0x08 : 0x00);
|
||||
result |= (MxM[4] ? 0x10 : 0x00);
|
||||
result |= (MxM[5] ? 0x20 : 0x00);
|
||||
result |= (MxM[6] ? 0x40 : 0x00);
|
||||
result |= (MxM[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxM ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxM ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxM ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxM ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxM ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxM ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxM ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxM ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x1F:
|
||||
result = (MxD[0] ? 0x01 : 0x00);
|
||||
result |= (MxD[1] ? 0x02 : 0x00);
|
||||
result |= (MxD[2] ? 0x04 : 0x00);
|
||||
result |= (MxD[3] ? 0x08 : 0x00);
|
||||
result |= (MxD[4] ? 0x10 : 0x00);
|
||||
result |= (MxD[5] ? 0x20 : 0x00);
|
||||
result |= (MxD[6] ? 0x40 : 0x00);
|
||||
result |= (MxD[7] ? 0x80 : 0x00);
|
||||
result = (Sprites[0].MxD ? 0x01 : 0x00);
|
||||
result |= (Sprites[1].MxD ? 0x02 : 0x00);
|
||||
result |= (Sprites[2].MxD ? 0x04 : 0x00);
|
||||
result |= (Sprites[3].MxD ? 0x08 : 0x00);
|
||||
result |= (Sprites[4].MxD ? 0x10 : 0x00);
|
||||
result |= (Sprites[5].MxD ? 0x20 : 0x00);
|
||||
result |= (Sprites[6].MxD ? 0x40 : 0x00);
|
||||
result |= (Sprites[7].MxD ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x20:
|
||||
result &= 0xF0;
|
||||
|
@ -247,7 +257,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x2D:
|
||||
case 0x2E:
|
||||
result &= 0xF0;
|
||||
result |= MxC[addr - 0x27] & 0x0F;
|
||||
result |= Sprites[addr - 0x27].MxC & 0x0F;
|
||||
break;
|
||||
default:
|
||||
result = 0xFF;
|
||||
|
@ -273,8 +283,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x0C:
|
||||
case 0x0E:
|
||||
index = addr >> 1;
|
||||
MxX[index] &= 0x100;
|
||||
MxX[index] |= (val & 0xFF);
|
||||
Sprites[index].MxX &= 0x100;
|
||||
Sprites[index].MxX |= (val & 0xFF);
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x03:
|
||||
|
@ -285,18 +295,18 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x0D:
|
||||
case 0x0F:
|
||||
index = addr >> 1;
|
||||
MxY[index] &= 0x100;
|
||||
MxY[index] |= (val & 0xFF);
|
||||
Sprites[index].MxY &= 0x100;
|
||||
Sprites[index].MxY |= (val & 0xFF);
|
||||
break;
|
||||
case 0x10:
|
||||
MxX[0] = (MxX[0] & 0xFF) | ((val & 0x01) << 8);
|
||||
MxX[1] = (MxX[1] & 0xFF) | ((val & 0x02) << 7);
|
||||
MxX[2] = (MxX[2] & 0xFF) | ((val & 0x04) << 6);
|
||||
MxX[3] = (MxX[3] & 0xFF) | ((val & 0x08) << 5);
|
||||
MxX[4] = (MxX[4] & 0xFF) | ((val & 0x10) << 4);
|
||||
MxX[5] = (MxX[5] & 0xFF) | ((val & 0x20) << 3);
|
||||
MxX[6] = (MxX[6] & 0xFF) | ((val & 0x40) << 2);
|
||||
MxX[7] = (MxX[7] & 0xFF) | ((val & 0x80) << 1);
|
||||
Sprites[0].MxX = (Sprites[0].MxX & 0xFF) | ((val & 0x01) << 8);
|
||||
Sprites[1].MxX = (Sprites[1].MxX & 0xFF) | ((val & 0x02) << 7);
|
||||
Sprites[2].MxX = (Sprites[2].MxX & 0xFF) | ((val & 0x04) << 6);
|
||||
Sprites[3].MxX = (Sprites[3].MxX & 0xFF) | ((val & 0x08) << 5);
|
||||
Sprites[4].MxX = (Sprites[4].MxX & 0xFF) | ((val & 0x10) << 4);
|
||||
Sprites[5].MxX = (Sprites[5].MxX & 0xFF) | ((val & 0x20) << 3);
|
||||
Sprites[6].MxX = (Sprites[6].MxX & 0xFF) | ((val & 0x40) << 2);
|
||||
Sprites[7].MxX = (Sprites[7].MxX & 0xFF) | ((val & 0x80) << 1);
|
||||
break;
|
||||
case 0x11:
|
||||
YSCROLL = (val & 0x07);
|
||||
|
@ -318,14 +328,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
LPY = (val & 0xFF);
|
||||
break;
|
||||
case 0x15:
|
||||
MxE[0] = ((val & 0x01) != 0x00);
|
||||
MxE[1] = ((val & 0x02) != 0x00);
|
||||
MxE[2] = ((val & 0x04) != 0x00);
|
||||
MxE[3] = ((val & 0x08) != 0x00);
|
||||
MxE[4] = ((val & 0x10) != 0x00);
|
||||
MxE[5] = ((val & 0x20) != 0x00);
|
||||
MxE[6] = ((val & 0x40) != 0x00);
|
||||
MxE[7] = ((val & 0x80) != 0x00);
|
||||
Sprites[0].MxE = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxE = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxE = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxE = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxE = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxE = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxE = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxE = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x16:
|
||||
XSCROLL = (val & 0x07);
|
||||
|
@ -334,14 +344,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
RES = ((val & 0x20) != 0x00);
|
||||
break;
|
||||
case 0x17:
|
||||
MxYE[0] = ((val & 0x01) != 0x00);
|
||||
MxYE[1] = ((val & 0x02) != 0x00);
|
||||
MxYE[2] = ((val & 0x04) != 0x00);
|
||||
MxYE[3] = ((val & 0x08) != 0x00);
|
||||
MxYE[4] = ((val & 0x10) != 0x00);
|
||||
MxYE[5] = ((val & 0x20) != 0x00);
|
||||
MxYE[6] = ((val & 0x40) != 0x00);
|
||||
MxYE[7] = ((val & 0x80) != 0x00);
|
||||
Sprites[0].MxYE = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxYE = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxYE = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxYE = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxYE = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxYE = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxYE = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxYE = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x18:
|
||||
CB = (val & 0x0E) >> 1;
|
||||
|
@ -360,54 +370,54 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
ELP = ((val & 0x08) != 0x00);
|
||||
break;
|
||||
case 0x1B:
|
||||
MxDP[0] = ((val & 0x01) != 0x00);
|
||||
MxDP[1] = ((val & 0x02) != 0x00);
|
||||
MxDP[2] = ((val & 0x04) != 0x00);
|
||||
MxDP[3] = ((val & 0x08) != 0x00);
|
||||
MxDP[4] = ((val & 0x10) != 0x00);
|
||||
MxDP[5] = ((val & 0x20) != 0x00);
|
||||
MxDP[6] = ((val & 0x40) != 0x00);
|
||||
MxDP[7] = ((val & 0x80) != 0x00);
|
||||
Sprites[0].MxDP = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxDP = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxDP = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxDP = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxDP = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxDP = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxDP = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxDP = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x1C:
|
||||
MxMC[0] = ((val & 0x01) != 0x00);
|
||||
MxMC[1] = ((val & 0x02) != 0x00);
|
||||
MxMC[2] = ((val & 0x04) != 0x00);
|
||||
MxMC[3] = ((val & 0x08) != 0x00);
|
||||
MxMC[4] = ((val & 0x10) != 0x00);
|
||||
MxMC[5] = ((val & 0x20) != 0x00);
|
||||
MxMC[6] = ((val & 0x40) != 0x00);
|
||||
MxMC[7] = ((val & 0x80) != 0x00);
|
||||
Sprites[0].MxMC = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxMC = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxMC = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxMC = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxMC = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxMC = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxMC = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxMC = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x1D:
|
||||
MxXE[0] = ((val & 0x01) != 0x00);
|
||||
MxXE[1] = ((val & 0x02) != 0x00);
|
||||
MxXE[2] = ((val & 0x04) != 0x00);
|
||||
MxXE[3] = ((val & 0x08) != 0x00);
|
||||
MxXE[4] = ((val & 0x10) != 0x00);
|
||||
MxXE[5] = ((val & 0x20) != 0x00);
|
||||
MxXE[6] = ((val & 0x40) != 0x00);
|
||||
MxXE[7] = ((val & 0x80) != 0x00);
|
||||
Sprites[0].MxXE = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxXE = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxXE = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxXE = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxXE = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxXE = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxXE = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxXE = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x1E:
|
||||
MxM[0] = ((val & 0x01) != 0x00);
|
||||
MxM[1] = ((val & 0x02) != 0x00);
|
||||
MxM[2] = ((val & 0x04) != 0x00);
|
||||
MxM[3] = ((val & 0x08) != 0x00);
|
||||
MxM[4] = ((val & 0x10) != 0x00);
|
||||
MxM[5] = ((val & 0x20) != 0x00);
|
||||
MxM[6] = ((val & 0x40) != 0x00);
|
||||
MxM[7] = ((val & 0x80) != 0x00);
|
||||
case 0x1E:
|
||||
Sprites[0].MxM = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxM = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxM = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxM = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxM = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxM = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxM = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxM = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x1F:
|
||||
MxD[0] = ((val & 0x01) != 0x00);
|
||||
MxD[1] = ((val & 0x02) != 0x00);
|
||||
MxD[2] = ((val & 0x04) != 0x00);
|
||||
MxD[3] = ((val & 0x08) != 0x00);
|
||||
MxD[4] = ((val & 0x10) != 0x00);
|
||||
MxD[5] = ((val & 0x20) != 0x00);
|
||||
MxD[6] = ((val & 0x40) != 0x00);
|
||||
MxD[7] = ((val & 0x80) != 0x00);
|
||||
Sprites[0].MxD = ((val & 0x01) != 0x00);
|
||||
Sprites[1].MxD = ((val & 0x02) != 0x00);
|
||||
Sprites[2].MxD = ((val & 0x04) != 0x00);
|
||||
Sprites[3].MxD = ((val & 0x08) != 0x00);
|
||||
Sprites[4].MxD = ((val & 0x10) != 0x00);
|
||||
Sprites[5].MxD = ((val & 0x20) != 0x00);
|
||||
Sprites[6].MxD = ((val & 0x40) != 0x00);
|
||||
Sprites[7].MxD = ((val & 0x80) != 0x00);
|
||||
break;
|
||||
case 0x20:
|
||||
EC = (val & 0x0F);
|
||||
|
@ -430,7 +440,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
case 0x2C:
|
||||
case 0x2D:
|
||||
case 0x2E:
|
||||
MxC[addr - 0x27] = val & 0x0F;
|
||||
Sprites[addr - 0x27].MxC = val & 0x0F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -503,6 +513,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public int spriteFetchStartCycle;
|
||||
public int spriteFetchIndex;
|
||||
public bool spriteForeground;
|
||||
public SpriteGenerator[] spriteGenerators;
|
||||
public int totalCycles;
|
||||
public bool vBlank;
|
||||
public int visibleBottom;
|
||||
|
@ -522,6 +533,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
private Action FetchG;
|
||||
private Func<int> Plotter;
|
||||
private Action PerformCycleFunction;
|
||||
private SpriteRegs[] sprites;
|
||||
|
||||
public VicII(ChipSignals newSignal, Region newRegion)
|
||||
{
|
||||
|
@ -649,6 +661,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
idle = true;
|
||||
refreshAddress = 0x3FFF;
|
||||
regs = new VicIIRegs();
|
||||
sprites = regs.Sprites;
|
||||
regs.RC = 7;
|
||||
signal.VicAEC = true;
|
||||
signal.VicIRQ = false;
|
||||
|
@ -659,6 +672,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
// some helpful values
|
||||
cyclesPerFrame = totalCycles * rasterTotalLines;
|
||||
|
||||
// initialize sprite generators
|
||||
spriteGenerators = new SpriteGenerator[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
spriteGenerators[i] = new SpriteGenerator(regs, i, rasterWidth, rasterLineLeft);
|
||||
}
|
||||
|
||||
public byte Peek(int addr)
|
||||
|
@ -710,8 +728,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
// sprite Y stretch flipflop
|
||||
for (int i = 0; i < 8; i++)
|
||||
if (!regs.MxYE[i])
|
||||
regs.MxYEToggle[i] = true;
|
||||
if (!sprites[i].MxYE)
|
||||
sprites[i].MxYEToggle = true;
|
||||
}
|
||||
|
||||
// operations timed to NTSC
|
||||
|
@ -773,6 +791,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
PerformDRAMRefresh();
|
||||
break;
|
||||
case 15:
|
||||
spriteGenerators[0].Render();
|
||||
spriteGenerators[1].Render();
|
||||
spriteGenerators[2].Render();
|
||||
spriteGenerators[3].Render();
|
||||
spriteGenerators[4].Render();
|
||||
spriteGenerators[5].Render();
|
||||
spriteGenerators[6].Render();
|
||||
spriteGenerators[7].Render();
|
||||
PerformSpriteMCBASEAdvance();
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
|
@ -971,27 +997,28 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
// sprite comparison
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (regs.MxE[i] == true && regs.MxY[i] == (regs.RASTER & 0xFF) && regs.MDMA[i] == false)
|
||||
if (sprites[i].MxE == true && sprites[i].MxY == (regs.RASTER & 0xFF) && sprites[i].MDMA == false)
|
||||
{
|
||||
regs.MDMA[i] = true;
|
||||
regs.MCBASE[i] = 0;
|
||||
if (regs.MxYE[i])
|
||||
regs.MxYEToggle[i] = false;
|
||||
sprites[i].MDMA = true;
|
||||
sprites[i].MCBASE = 0;
|
||||
if (sprites[i].MxYE)
|
||||
sprites[i].MxYEToggle = false;
|
||||
}
|
||||
regs.MxXEToggle[i] = false;
|
||||
sprites[i].MxXEToggle = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformSpriteDataFetch(int spriteIndex)
|
||||
{
|
||||
// second half of the fetch cycle
|
||||
if (regs.MDMA[spriteIndex])
|
||||
signal.VicAEC = !sprites[spriteIndex].MDMA;
|
||||
if (sprites[spriteIndex].MDMA)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
regs.MSR[spriteIndex] <<= 8;
|
||||
regs.MSR[spriteIndex] |= mem.VicRead((ushort)((regs.MPTR[spriteIndex] << 6) | (regs.MC[spriteIndex])));
|
||||
regs.MC[spriteIndex]++;
|
||||
sprites[spriteIndex].MSR <<= 8;
|
||||
sprites[spriteIndex].MSR |= mem.VicRead((ushort)((sprites[spriteIndex].MPTR << 6) | (sprites[spriteIndex].MC)));
|
||||
sprites[spriteIndex].MC++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1001,11 +1028,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
// sprite MC processing
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
regs.MC[i] = regs.MCBASE[i];
|
||||
if (regs.MDMA[i] && regs.MxY[i] == (regs.RASTER & 0xFF))
|
||||
sprites[i].MC = sprites[i].MCBASE;
|
||||
if (sprites[i].MDMA && sprites[i].MxY == (regs.RASTER & 0xFF))
|
||||
{
|
||||
regs.MD[i] = true;
|
||||
regs.MxXEToggle[i] = false;
|
||||
sprites[i].MD = true;
|
||||
sprites[i].MxXEToggle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1014,13 +1041,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (regs.MxYEToggle[i])
|
||||
if (sprites[i].MxYEToggle)
|
||||
{
|
||||
regs.MCBASE[i] += 3;
|
||||
if (regs.MxYEToggle[i] && regs.MCBASE[i] == 63)
|
||||
sprites[i].MCBASE += 3;
|
||||
if (sprites[i].MxYEToggle && sprites[i].MCBASE == 63)
|
||||
{
|
||||
regs.MD[i] = false;
|
||||
regs.MDMA[i] = false;
|
||||
sprites[i].MD = false;
|
||||
sprites[i].MDMA = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1030,23 +1057,23 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
{
|
||||
// first half of the fetch cycle, always fetch pointer
|
||||
ushort pointerOffset = (ushort)((regs.VM << 10) | 0x3F8 | spriteIndex);
|
||||
regs.MPTR[spriteIndex] = mem.VicRead(pointerOffset);
|
||||
sprites[spriteIndex].MPTR = mem.VicRead(pointerOffset);
|
||||
|
||||
// also fetch upper 8 bits if enabled
|
||||
signal.VicAEC = !regs.MDMA[spriteIndex];
|
||||
if (regs.MDMA[spriteIndex])
|
||||
signal.VicAEC = !sprites[spriteIndex].MDMA;
|
||||
if (sprites[spriteIndex].MDMA)
|
||||
{
|
||||
regs.MSRC[spriteIndex] = 24;
|
||||
regs.MSR[spriteIndex] = mem.VicRead((ushort)((regs.MPTR[spriteIndex] << 6) | (regs.MC[spriteIndex])));
|
||||
regs.MC[spriteIndex]++;
|
||||
sprites[spriteIndex].MSRC = 24;
|
||||
sprites[spriteIndex].MSR = mem.VicRead((ushort)((sprites[spriteIndex].MPTR << 6) | (sprites[spriteIndex].MC)));
|
||||
sprites[spriteIndex].MC++;
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformSpriteYExpansionFlip()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
if (regs.MxYE[i])
|
||||
regs.MxYEToggle[i] = !regs.MxYEToggle[i];
|
||||
if (sprites[i].MxYE)
|
||||
sprites[i].MxYEToggle = !sprites[i].MxYEToggle;
|
||||
}
|
||||
|
||||
private void PerformVCReset()
|
||||
|
@ -1294,87 +1321,35 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if (regs.MD[j])
|
||||
if (spriteGenerators[j].hasData)
|
||||
{
|
||||
if (regs.MxX[j] == rasterOffsetX)
|
||||
if (spriteGenerators[j].dataBuffer[rasterOffsetX] != 0)
|
||||
{
|
||||
regs.MSRA[j] = true;
|
||||
regs.MxXLatch[j] = rasterOffsetX;
|
||||
}
|
||||
if (regs.MSRA[j])
|
||||
{
|
||||
// multicolor consumes two bits per pixel and is forced wide
|
||||
if (regs.MxMC[j])
|
||||
{
|
||||
spriteBits = (int)((regs.MSR[j] >> 22) & 0x3);
|
||||
if ((rasterOffsetX & 0x1) != (regs.MxXLatch[j] & 0x1))
|
||||
{
|
||||
if (!regs.MxXE[j] || regs.MxXEToggle[j])
|
||||
{
|
||||
regs.MSR[j] <<= 2;
|
||||
regs.MSRC[j]--;
|
||||
}
|
||||
regs.MxXEToggle[j] = !regs.MxXEToggle[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteBits = (int)((regs.MSR[j] >> 22) & 0x2);
|
||||
if (!regs.MxXE[j] || regs.MxXEToggle[j])
|
||||
{
|
||||
regs.MSR[j] <<= 1;
|
||||
regs.MSRC[j]--;
|
||||
}
|
||||
regs.MxXEToggle[j] = !regs.MxXEToggle[j];
|
||||
}
|
||||
|
||||
// if not transparent, process collisions and color
|
||||
if (spriteBits != 0)
|
||||
// process collisions if the border is off
|
||||
if (!borderOnVertical)
|
||||
{
|
||||
switch (spriteBits)
|
||||
if (spritePixelOwner == -1)
|
||||
{
|
||||
case 1:
|
||||
spritePixel = regs.MMx[0];
|
||||
break;
|
||||
case 2:
|
||||
spritePixel = regs.MxC[j];
|
||||
break;
|
||||
case 3:
|
||||
spritePixel = regs.MMx[1];
|
||||
break;
|
||||
default:
|
||||
// this should never happen but VS needs this
|
||||
spritePixel = 0;
|
||||
break;
|
||||
spritePixelOwner = j;
|
||||
if (!sprites[j].MxDP || (!pixelBufferForeground[pixelBufferIndex]))
|
||||
{
|
||||
outputPixel = spriteGenerators[j].colorBuffer[rasterOffsetX];
|
||||
}
|
||||
}
|
||||
|
||||
// process collisions if the border is off
|
||||
if (!borderOnVertical)
|
||||
else
|
||||
{
|
||||
if (spritePixelOwner == -1)
|
||||
{
|
||||
spritePixelOwner = j;
|
||||
if (!regs.MxDP[j] || (!pixelBufferForeground[pixelBufferIndex]))
|
||||
{
|
||||
outputPixel = spritePixel;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// a sprite already occupies this space
|
||||
regs.MxM[spritePixelOwner] = true;
|
||||
regs.MxM[j] = true;
|
||||
regs.IMMC = true;
|
||||
}
|
||||
if (pixelBufferForeground[pixelBufferIndex])
|
||||
{
|
||||
regs.MxD[j] = true;
|
||||
regs.IMBC = true;
|
||||
}
|
||||
// a sprite already occupies this space
|
||||
sprites[spritePixelOwner].MxM = true;
|
||||
sprites[j].MxM = true;
|
||||
regs.IMMC = true;
|
||||
}
|
||||
if (pixelBufferForeground[pixelBufferIndex])
|
||||
{
|
||||
sprites[j].MxD = true;
|
||||
regs.IMBC = true;
|
||||
}
|
||||
}
|
||||
if (regs.MSRC[j] == 0)
|
||||
regs.MSRA[j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Computers.Commodore64
|
||||
{
|
||||
public partial class VicII : IVideoProvider
|
||||
{
|
||||
public class BackgroundGenerator
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Computers.Commodore64
|
||||
{
|
||||
public partial class VicII : IVideoProvider
|
||||
{
|
||||
public class SpriteGenerator
|
||||
{
|
||||
private int color;
|
||||
private int data;
|
||||
private bool enabled = false;
|
||||
private bool mc;
|
||||
private int mmx0;
|
||||
private int mmx1;
|
||||
private int msr;
|
||||
private int msrc;
|
||||
private int mxc;
|
||||
private int rasterLeft;
|
||||
private int rasterX;
|
||||
private int rasterWidth;
|
||||
private VicIIRegs regs;
|
||||
private SpriteRegs sprite;
|
||||
private int x;
|
||||
private bool xe;
|
||||
private bool xeToggle;
|
||||
|
||||
public int[] colorBuffer;
|
||||
public int[] dataBuffer;
|
||||
public bool hasData;
|
||||
public int spriteNumber;
|
||||
|
||||
public SpriteGenerator(VicIIRegs newRegs, int newNumber, int newRasterWidth, int newRasterLeft)
|
||||
{
|
||||
spriteNumber = newNumber;
|
||||
regs = newRegs;
|
||||
sprite = regs.Sprites[spriteNumber];
|
||||
|
||||
rasterWidth = newRasterWidth;
|
||||
rasterLeft = newRasterLeft;
|
||||
colorBuffer = new int[rasterWidth];
|
||||
dataBuffer = new int[rasterWidth];
|
||||
rasterX = rasterLeft;
|
||||
}
|
||||
|
||||
// render a scanline of a sprite
|
||||
public void Render()
|
||||
{
|
||||
hasData = false;
|
||||
enabled = false;
|
||||
mc = sprite.MxMC;
|
||||
mmx0 = regs.MMx[0];
|
||||
mmx1 = regs.MMx[1];
|
||||
msr = sprite.MSR;
|
||||
msrc = 24;
|
||||
mxc = sprite.MxC;
|
||||
x = sprite.MxX;
|
||||
xe = sprite.MxXE;
|
||||
|
||||
xeToggle = !xe;
|
||||
for (int i = 0; i < rasterWidth; i++)
|
||||
{
|
||||
if (rasterX == x)
|
||||
{
|
||||
enabled = sprite.MD;
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (mc)
|
||||
{
|
||||
data = ((msr >> 22) & 0x3);
|
||||
if ((rasterX & 0x1) != (x & 0x1))
|
||||
{
|
||||
if (!xe || xeToggle)
|
||||
{
|
||||
msr <<= 2;
|
||||
msrc--;
|
||||
}
|
||||
xeToggle = !xeToggle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = ((msr >> 22) & 0x2);
|
||||
if (!xe || xeToggle)
|
||||
{
|
||||
msr <<= 1;
|
||||
msrc--;
|
||||
}
|
||||
xeToggle = !xeToggle;
|
||||
}
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
color = 0;
|
||||
break;
|
||||
case 1:
|
||||
color = mmx0;
|
||||
break;
|
||||
case 2:
|
||||
color = mxc;
|
||||
break;
|
||||
case 3:
|
||||
color = mmx1;
|
||||
break;
|
||||
}
|
||||
|
||||
dataBuffer[rasterX] = data;
|
||||
colorBuffer[rasterX] = color;
|
||||
hasData |= (data != 0);
|
||||
|
||||
if (msrc == 0)
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataBuffer[rasterX] = 0;
|
||||
}
|
||||
|
||||
rasterX++;
|
||||
if (rasterX >= rasterWidth)
|
||||
rasterX = 0;
|
||||
}
|
||||
sprite.MSR = msr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue