From 30d18601ba84f545addee2fcb4619e99e56869eb Mon Sep 17 00:00:00 2001 From: saxxonpike Date: Tue, 13 Nov 2012 16:11:31 +0000 Subject: [PATCH] commodore64: VIC sprite renderer fixed (shows line 21), SID noise shift register fixed (proper output frequency) --- BizHawk.Emulation/BizHawk.Emulation.csproj | 2 + .../Computers/Commodore64/Sid.cs | 240 +++++---- .../Computers/Commodore64/SidSoundProvider.cs | 8 +- .../Computers/Commodore64/VicII.cs | 493 +++++++++--------- .../Commodore64/VicIIBackgroundGenerator.cs | 14 + .../Commodore64/VicIISpriteGenerator.cs | 133 +++++ 6 files changed, 521 insertions(+), 369 deletions(-) create mode 100644 BizHawk.Emulation/Computers/Commodore64/VicIIBackgroundGenerator.cs create mode 100644 BizHawk.Emulation/Computers/Commodore64/VicIISpriteGenerator.cs diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 681e5b5168..9147b2aa70 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -93,6 +93,8 @@ + + diff --git a/BizHawk.Emulation/Computers/Commodore64/Sid.cs b/BizHawk.Emulation/Computers/Commodore64/Sid.cs index d9fb3b77dc..354ad1dec9 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Sid.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Sid.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 ReadPotX; public Func 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) | diff --git a/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs b/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs index 72571b8143..1aeca36db3 100644 --- a/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs +++ b/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs @@ -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++) diff --git a/BizHawk.Emulation/Computers/Commodore64/VicII.cs b/BizHawk.Emulation/Computers/Commodore64/VicII.cs index febbc175d5..a5baf1118e 100644 --- a/BizHawk.Emulation/Computers/Commodore64/VicII.cs +++ b/BizHawk.Emulation/Computers/Commodore64/VicII.cs @@ -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 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; } } } diff --git a/BizHawk.Emulation/Computers/Commodore64/VicIIBackgroundGenerator.cs b/BizHawk.Emulation/Computers/Commodore64/VicIIBackgroundGenerator.cs new file mode 100644 index 0000000000..79eb6f4860 --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/VicIIBackgroundGenerator.cs @@ -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 + { + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/VicIISpriteGenerator.cs b/BizHawk.Emulation/Computers/Commodore64/VicIISpriteGenerator.cs new file mode 100644 index 0000000000..686a04f66c --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/VicIISpriteGenerator.cs @@ -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; + } + } + } +}