commodore64: VIC sprite renderer fixed (shows line 21), SID noise shift register fixed (proper output frequency)

This commit is contained in:
saxxonpike 2012-11-13 16:11:31 +00:00
parent 607998ddd9
commit 30d18601ba
6 changed files with 521 additions and 369 deletions

View File

@ -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" />

View File

@ -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) |

View File

@ -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++)

View File

@ -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;
}
}
}

View File

@ -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
{
}
}
}

View File

@ -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;
}
}
}
}