diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 8acaf4e95b..4e00fb1dfc 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -152,6 +152,10 @@
+
+
+
+
diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Parse.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Parse.cs
new file mode 100644
index 0000000000..4ec039a631
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Parse.cs
@@ -0,0 +1,235 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64.MOS
+{
+ public abstract partial class Vic
+ {
+ private int parseaddr;
+ private int parsecycleBAsprite0;
+ private int parsecycleBAsprite1;
+ private int parsecycleBAsprite2;
+ private int parsecycleFetchSpriteIndex;
+ private int parsefetch;
+ private int parseba;
+ private int parseact;
+
+ private void ParseCycle()
+ {
+
+ {
+ parseaddr = 0x3FFF;
+ parsefetch = pipeline[1][cycleIndex];
+ parseba = pipeline[2][cycleIndex];
+ parseact = pipeline[3][cycleIndex];
+
+ // apply X location
+ rasterX = pipeline[0][cycleIndex];
+
+ // perform fetch
+ switch (parsefetch & 0xFF00)
+ {
+ case 0x0100:
+ // fetch R
+ refreshCounter = (refreshCounter - 1) & 0xFF;
+ parseaddr = (0x3F00 | refreshCounter);
+ ReadMemory(parseaddr);
+ break;
+ case 0x0200:
+ // fetch C
+ if (!idle)
+ {
+ if (badline)
+ {
+ parseaddr = ((pointerVM << 10) | vc);
+ dataC = ReadMemory(parseaddr);
+ dataC |= ((int)ReadColorRam(parseaddr) & 0xF) << 8;
+ bufferC[vmli] = dataC;
+ }
+ else
+ {
+ dataC = bufferC[vmli];
+ }
+ }
+ else
+ {
+ dataC = 0;
+ bufferC[vmli] = dataC;
+ }
+ break;
+ case 0x0300:
+ // fetch G
+ if (idle)
+ parseaddr = 0x3FFF;
+ else
+ {
+ if (bitmapMode)
+ parseaddr = (rc | (vc << 3) | ((pointerCB & 0x4) << 11));
+ else
+ parseaddr = (rc | ((dataC & 0xFF) << 3) | (pointerCB << 11));
+ }
+ if (extraColorMode)
+ parseaddr &= 0x39FF;
+ dataG = ReadMemory(parseaddr);
+ if (!idle)
+ {
+ bufferG[vmli] = dataG;
+ vmli = (vmli + 1) & 0x3F;
+ vc = (vc + 1) & 0x3FF;
+ }
+ break;
+ case 0x0400:
+ // fetch I
+ parseaddr = (extraColorMode ? 0x39FF : 0x3FFF);
+ dataG = ReadMemory(parseaddr);
+ dataC = 0;
+ break;
+ case 0x0500:
+ // no fetch
+ break;
+ default:
+ parsecycleFetchSpriteIndex = (parsefetch & 0x7);
+ switch (parsefetch & 0xF0)
+ {
+ case 0x00:
+ // fetch P
+ parseaddr = (0x3F8 | (pointerVM << 10) | parsecycleFetchSpriteIndex);
+ sprites[parsecycleFetchSpriteIndex].pointer = ReadMemory(parseaddr);
+ sprites[parsecycleFetchSpriteIndex].shiftEnable = false;
+ break;
+ case 0x10:
+ case 0x20:
+ case 0x30:
+ // fetch S
+ if (sprites[parsecycleFetchSpriteIndex].dma)
+ {
+ Sprite spr = sprites[parsecycleFetchSpriteIndex];
+ parseaddr = (spr.mc | (spr.pointer << 6));
+ spr.sr <<= 8;
+ spr.sr |= ReadMemory(parseaddr);
+ spr.mc++;
+ }
+ break;
+ }
+ break;
+ }
+
+ // perform BA flag manipulation
+ switch (parseba)
+ {
+ case 0x0000:
+ pinBA = true;
+ break;
+ case 0x1000:
+ pinBA = !badline;
+ break;
+ default:
+ parsecycleBAsprite0 = (parseba & 0x000F);
+ parsecycleBAsprite1 = (parseba & 0x00F0) >> 4;
+ parsecycleBAsprite2 = (parseba & 0x0F00) >> 8;
+ if ((parsecycleBAsprite0 < 8 && sprites[parsecycleBAsprite0].dma) ||
+ (parsecycleBAsprite1 < 8 && sprites[parsecycleBAsprite1].dma) ||
+ (parsecycleBAsprite2 < 8 && sprites[parsecycleBAsprite2].dma))
+ pinBA = false;
+ else
+ pinBA = true;
+ break;
+ }
+
+ // perform actions
+ borderCheckLEnable = true;
+ borderCheckREnable = true;
+
+ if ((parseact & pipelineChkSprChunch) != 0)
+ {
+ //for (int i = 0; i < 8; i++)
+ foreach (Sprite spr in sprites)
+ {
+ //Sprite spr = sprites[i];
+ if (spr.yCrunch)
+ spr.mcbase += 2;
+ spr.shiftEnable = false;
+ spr.xCrunch = !spr.xExpand;
+ spr.multicolorCrunch = !spr.multicolor;
+ }
+ }
+ if ((parseact & pipelineChkSprDisp) != 0)
+ {
+ //for (int i = 0; i < 8; i++)
+ foreach (Sprite spr in sprites)
+ {
+ //Sprite spr = sprites[i];
+ spr.mc = spr.mcbase;
+ if (spr.dma && spr.y == (rasterLine & 0xFF))
+ {
+ spr.display = true;
+ }
+ }
+ }
+ if ((parseact & pipelineChkSprDma) != 0)
+ {
+ //for (int i = 0; i < 8; i++)
+ foreach (Sprite spr in sprites)
+ {
+ //Sprite spr = sprites[i];
+ if (spr.enable && spr.y == (rasterLine & 0xFF) && !spr.dma)
+ {
+ spr.dma = true;
+ spr.mcbase = 0;
+ spr.yCrunch = !spr.yExpand;
+ }
+ }
+ }
+ if ((parseact & pipelineChkSprExp) != 0)
+ {
+ if (sprites[0].yExpand) sprites[0].yCrunch ^= true;
+ if (sprites[1].yExpand) sprites[1].yCrunch ^= true;
+ if (sprites[2].yExpand) sprites[2].yCrunch ^= true;
+ if (sprites[3].yExpand) sprites[3].yCrunch ^= true;
+ if (sprites[4].yExpand) sprites[4].yCrunch ^= true;
+ if (sprites[5].yExpand) sprites[5].yCrunch ^= true;
+ if (sprites[6].yExpand) sprites[6].yCrunch ^= true;
+ if (sprites[7].yExpand) sprites[7].yCrunch ^= true;
+ }
+ if ((parseact & pipelineUpdateMcBase) != 0)
+ {
+ //for (int i = 0; i < 8; i++)
+ foreach (Sprite spr in sprites)
+ {
+ //Sprite spr = sprites[i];
+ if (spr.yCrunch)
+ {
+ spr.mcbase++;
+ if (spr.mcbase == 63)
+ {
+ spr.dma = false;
+ spr.display = false;
+ }
+ }
+ }
+ }
+ if ((parseact & pipelineUpdateRc) != 0)
+ {
+ if (rc == 7)
+ {
+ idle = true;
+ vcbase = vc;
+ }
+ if (!idle)
+ rc = (rc + 1) & 0x7;
+ }
+ if ((parseact & pipelineUpdateVc) != 0)
+ {
+ vc = vcbase;
+ vmli = 0;
+ if (badline)
+ rc = 0;
+ }
+
+ cycleIndex++;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Registers.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Registers.cs
new file mode 100644
index 0000000000..3b22a5484c
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Registers.cs
@@ -0,0 +1,528 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64.MOS
+{
+ public abstract partial class Vic
+ {
+ private int backgroundColor0;
+ private int backgroundColor1;
+ private int backgroundColor2;
+ private int backgroundColor3;
+ private bool bitmapMode;
+ private int borderColor;
+ private bool columnSelect;
+ private bool displayEnable;
+ private bool enableIntLightPen;
+ private bool enableIntRaster;
+ private bool enableIntSpriteCollision;
+ private bool enableIntSpriteDataCollision;
+ private bool extraColorMode;
+ private bool intLightPen;
+ private bool intRaster;
+ private bool intSpriteCollision;
+ private bool intSpriteDataCollision;
+ private int lightPenX;
+ private int lightPenY;
+ private bool multicolorMode;
+ private int pointerCB;
+ private int pointerVM;
+ private int rasterInterruptLine;
+ private int rasterLine;
+ private int rasterX;
+ private bool rowSelect;
+ private int spriteMulticolor0;
+ private int spriteMulticolor1;
+ private Sprite[] sprites;
+ private int xScroll;
+ private int yScroll;
+
+ public byte Peek(int addr)
+ {
+ return ReadRegister((addr & 0x3F));
+ }
+
+ public void Poke(int addr, byte val)
+ {
+ WriteRegister((addr & 0x3F), val);
+ }
+
+ public byte Read(int addr)
+ {
+ byte result;
+ addr &= 0x3F;
+
+ switch (addr)
+ {
+ case 0x1E:
+ case 0x1F:
+ // reading clears these
+ result = ReadRegister(addr);
+ WriteRegister(addr, 0);
+ break;
+ default:
+ result = ReadRegister((addr & 0x3F));
+ break;
+ }
+ return result;
+ }
+
+ private byte ReadRegister(int addr)
+ {
+ byte result = 0xFF; //unused bit value
+
+ switch (addr)
+ {
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0A:
+ case 0x0C:
+ case 0x0E:
+ result = (byte)(sprites[addr >> 1].x & 0xFF);
+ break;
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0B:
+ case 0x0D:
+ case 0x0F:
+ result = (byte)(sprites[addr >> 1].y & 0xFF);
+ break;
+ case 0x10:
+ result = (byte)(
+ ((sprites[0].x >> 8) & 0x01) |
+ ((sprites[1].x >> 7) & 0x02) |
+ ((sprites[2].x >> 6) & 0x04) |
+ ((sprites[3].x >> 5) & 0x08) |
+ ((sprites[4].x >> 4) & 0x10) |
+ ((sprites[5].x >> 3) & 0x20) |
+ ((sprites[6].x >> 2) & 0x40) |
+ ((sprites[7].x >> 1) & 0x80)
+ );
+ break;
+ case 0x11:
+ result = (byte)(
+ (yScroll & 0x7) |
+ (rowSelect ? 0x08 : 0x00) |
+ (displayEnable ? 0x10 : 0x00) |
+ (bitmapMode ? 0x20 : 0x00) |
+ (extraColorMode ? 0x40 : 0x00) |
+ ((rasterLine & 0x100) >> 1)
+ );
+ break;
+ case 0x12:
+ result = (byte)(rasterLine & 0xFF);
+ break;
+ case 0x13:
+ result = (byte)(lightPenX & 0xFF);
+ break;
+ case 0x14:
+ result = (byte)(lightPenY & 0xFF);
+ break;
+ case 0x15:
+ result = (byte)(
+ (sprites[0].enable ? 0x01 : 0x00) |
+ (sprites[1].enable ? 0x02 : 0x00) |
+ (sprites[2].enable ? 0x04 : 0x00) |
+ (sprites[3].enable ? 0x08 : 0x00) |
+ (sprites[4].enable ? 0x10 : 0x00) |
+ (sprites[5].enable ? 0x20 : 0x00) |
+ (sprites[6].enable ? 0x40 : 0x00) |
+ (sprites[7].enable ? 0x80 : 0x00)
+ );
+ break;
+ case 0x16:
+ result &= 0xC0;
+ result |= (byte)(
+ (xScroll & 0x7) |
+ (columnSelect ? 0x08 : 0x00) |
+ (multicolorMode ? 0x10 : 0x00)
+ );
+ break;
+ case 0x17:
+ result = (byte)(
+ (sprites[0].yExpand ? 0x01 : 0x00) |
+ (sprites[1].yExpand ? 0x02 : 0x00) |
+ (sprites[2].yExpand ? 0x04 : 0x00) |
+ (sprites[3].yExpand ? 0x08 : 0x00) |
+ (sprites[4].yExpand ? 0x10 : 0x00) |
+ (sprites[5].yExpand ? 0x20 : 0x00) |
+ (sprites[6].yExpand ? 0x40 : 0x00) |
+ (sprites[7].yExpand ? 0x80 : 0x00)
+ );
+ break;
+ case 0x18:
+ result &= 0x01;
+ result |= (byte)(
+ ((pointerVM & 0xF) << 4) |
+ ((pointerCB & 0x7) << 1)
+ );
+ break;
+ case 0x19:
+ result &= 0x70;
+ result |= (byte)(
+ (intRaster ? 0x01 : 0x00) |
+ (intSpriteDataCollision ? 0x02 : 0x00) |
+ (intSpriteCollision ? 0x04 : 0x00) |
+ (intLightPen ? 0x08 : 0x00) |
+ (pinIRQ ? 0x00 : 0x80)
+ );
+ break;
+ case 0x1A:
+ result &= 0xF0;
+ result |= (byte)(
+ (enableIntRaster ? 0x01 : 0x00) |
+ (enableIntSpriteDataCollision ? 0x02 : 0x00) |
+ (enableIntSpriteCollision ? 0x04 : 0x00) |
+ (enableIntLightPen ? 0x08 : 0x00)
+ );
+ break;
+ case 0x1B:
+ result = (byte)(
+ (sprites[0].priority ? 0x01 : 0x00) |
+ (sprites[1].priority ? 0x02 : 0x00) |
+ (sprites[2].priority ? 0x04 : 0x00) |
+ (sprites[3].priority ? 0x08 : 0x00) |
+ (sprites[4].priority ? 0x10 : 0x00) |
+ (sprites[5].priority ? 0x20 : 0x00) |
+ (sprites[6].priority ? 0x40 : 0x00) |
+ (sprites[7].priority ? 0x80 : 0x00)
+ );
+ break;
+ case 0x1C:
+ result = (byte)(
+ (sprites[0].multicolor ? 0x01 : 0x00) |
+ (sprites[1].multicolor ? 0x02 : 0x00) |
+ (sprites[2].multicolor ? 0x04 : 0x00) |
+ (sprites[3].multicolor ? 0x08 : 0x00) |
+ (sprites[4].multicolor ? 0x10 : 0x00) |
+ (sprites[5].multicolor ? 0x20 : 0x00) |
+ (sprites[6].multicolor ? 0x40 : 0x00) |
+ (sprites[7].multicolor ? 0x80 : 0x00)
+ );
+ break;
+ case 0x1D:
+ result = (byte)(
+ (sprites[0].xExpand ? 0x01 : 0x00) |
+ (sprites[1].xExpand ? 0x02 : 0x00) |
+ (sprites[2].xExpand ? 0x04 : 0x00) |
+ (sprites[3].xExpand ? 0x08 : 0x00) |
+ (sprites[4].xExpand ? 0x10 : 0x00) |
+ (sprites[5].xExpand ? 0x20 : 0x00) |
+ (sprites[6].xExpand ? 0x40 : 0x00) |
+ (sprites[7].xExpand ? 0x80 : 0x00)
+ );
+ break;
+ case 0x1E:
+ result = (byte)(
+ (sprites[0].collideSprite ? 0x01 : 0x00) |
+ (sprites[1].collideSprite ? 0x02 : 0x00) |
+ (sprites[2].collideSprite ? 0x04 : 0x00) |
+ (sprites[3].collideSprite ? 0x08 : 0x00) |
+ (sprites[4].collideSprite ? 0x10 : 0x00) |
+ (sprites[5].collideSprite ? 0x20 : 0x00) |
+ (sprites[6].collideSprite ? 0x40 : 0x00) |
+ (sprites[7].collideSprite ? 0x80 : 0x00)
+ );
+ break;
+ case 0x1F:
+ result = (byte)(
+ (sprites[0].collideData ? 0x01 : 0x00) |
+ (sprites[1].collideData ? 0x02 : 0x00) |
+ (sprites[2].collideData ? 0x04 : 0x00) |
+ (sprites[3].collideData ? 0x08 : 0x00) |
+ (sprites[4].collideData ? 0x10 : 0x00) |
+ (sprites[5].collideData ? 0x20 : 0x00) |
+ (sprites[6].collideData ? 0x40 : 0x00) |
+ (sprites[7].collideData ? 0x80 : 0x00)
+ );
+ break;
+ case 0x20:
+ result &= 0xF0;
+ result |= (byte)(borderColor & 0x0F);
+ break;
+ case 0x21:
+ result &= 0xF0;
+ result |= (byte)(backgroundColor0 & 0x0F);
+ break;
+ case 0x22:
+ result &= 0xF0;
+ result |= (byte)(backgroundColor1 & 0x0F);
+ break;
+ case 0x23:
+ result &= 0xF0;
+ result |= (byte)(backgroundColor2 & 0x0F);
+ break;
+ case 0x24:
+ result &= 0xF0;
+ result |= (byte)(backgroundColor3 & 0x0F);
+ break;
+ case 0x25:
+ result &= 0xF0;
+ result |= (byte)(spriteMulticolor0 & 0x0F);
+ break;
+ case 0x26:
+ result &= 0xF0;
+ result |= (byte)(spriteMulticolor1 & 0x0F);
+ break;
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ result &= 0xF0;
+ result |= (byte)(sprites[addr - 0x27].color & 0xF);
+ break;
+ default:
+ // not connected
+ break;
+ }
+
+ return result;
+ }
+
+ public void Write(int addr, byte val)
+ {
+ addr &= 0x3F;
+ switch (addr)
+ {
+ case 0x19:
+ // interrupts are cleared by writing a 1
+ if ((val & 0x01) != 0)
+ intRaster = false;
+ if ((val & 0x02) != 0)
+ intSpriteDataCollision = false;
+ if ((val & 0x04) != 0)
+ intSpriteCollision = false;
+ if ((val & 0x08) != 0)
+ intLightPen = false;
+ UpdatePins();
+ break;
+ case 0x1A:
+ WriteRegister(addr, val);
+ break;
+ case 0x1E:
+ case 0x1F:
+ // can't write to these
+ break;
+ case 0x2F:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ // not connected
+ break;
+ default:
+ WriteRegister(addr, val);
+ break;
+ }
+ }
+
+ private void WriteRegister(int addr, byte val)
+ {
+ switch (addr)
+ {
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0A:
+ case 0x0C:
+ case 0x0E:
+ sprites[addr >> 1].x &= 0x100;
+ sprites[addr >> 1].x |= val;
+ break;
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0B:
+ case 0x0D:
+ case 0x0F:
+ sprites[addr >> 1].y = val;
+ break;
+ case 0x10:
+ sprites[0].x = (sprites[0].x & 0xFF) | ((val & 0x01) << 8);
+ sprites[1].x = (sprites[1].x & 0xFF) | ((val & 0x02) << 7);
+ sprites[2].x = (sprites[2].x & 0xFF) | ((val & 0x04) << 6);
+ sprites[3].x = (sprites[3].x & 0xFF) | ((val & 0x08) << 5);
+ sprites[4].x = (sprites[4].x & 0xFF) | ((val & 0x10) << 4);
+ sprites[5].x = (sprites[5].x & 0xFF) | ((val & 0x20) << 3);
+ sprites[6].x = (sprites[6].x & 0xFF) | ((val & 0x40) << 2);
+ sprites[7].x = (sprites[7].x & 0xFF) | ((val & 0x80) << 1);
+ break;
+ case 0x11:
+ yScroll = (val & 0x07);
+ rowSelect = ((val & 0x08) != 0);
+ displayEnable = ((val & 0x10) != 0);
+ bitmapMode = ((val & 0x20) != 0);
+ extraColorMode = ((val & 0x40) != 0);
+ rasterInterruptLine &= 0xFF;
+ rasterInterruptLine |= (val & 0x80) << 1;
+ UpdateBorder();
+ break;
+ case 0x12:
+ rasterInterruptLine &= 0x100;
+ rasterInterruptLine |= val;
+ break;
+ case 0x13:
+ lightPenX = val;
+ break;
+ case 0x14:
+ lightPenY = val;
+ break;
+ case 0x15:
+ sprites[0].enable = ((val & 0x01) != 0);
+ sprites[1].enable = ((val & 0x02) != 0);
+ sprites[2].enable = ((val & 0x04) != 0);
+ sprites[3].enable = ((val & 0x08) != 0);
+ sprites[4].enable = ((val & 0x10) != 0);
+ sprites[5].enable = ((val & 0x20) != 0);
+ sprites[6].enable = ((val & 0x40) != 0);
+ sprites[7].enable = ((val & 0x80) != 0);
+ break;
+ case 0x16:
+ xScroll = (val & 0x07);
+ columnSelect = ((val & 0x08) != 0);
+ multicolorMode = ((val & 0x10) != 0);
+ UpdateBorder();
+ break;
+ case 0x17:
+ sprites[0].yExpand = ((val & 0x01) != 0);
+ sprites[1].yExpand = ((val & 0x02) != 0);
+ sprites[2].yExpand = ((val & 0x04) != 0);
+ sprites[3].yExpand = ((val & 0x08) != 0);
+ sprites[4].yExpand = ((val & 0x10) != 0);
+ sprites[5].yExpand = ((val & 0x20) != 0);
+ sprites[6].yExpand = ((val & 0x40) != 0);
+ sprites[7].yExpand = ((val & 0x80) != 0);
+ break;
+ case 0x18:
+ pointerVM = ((val >> 4) & 0xF);
+ pointerCB = ((val >> 1) & 0x7);
+ break;
+ case 0x19:
+ intRaster = ((val & 0x01) != 0);
+ intSpriteDataCollision = ((val & 0x02) != 0);
+ intSpriteCollision = ((val & 0x04) != 0);
+ intLightPen = ((val & 0x08) != 0);
+ UpdatePins();
+ break;
+ case 0x1A:
+ enableIntRaster = ((val & 0x01) != 0);
+ enableIntSpriteDataCollision = ((val & 0x02) != 0);
+ enableIntSpriteCollision = ((val & 0x04) != 0);
+ enableIntLightPen = ((val & 0x08) != 0);
+ UpdatePins();
+ break;
+ case 0x1B:
+ sprites[0].priority = ((val & 0x01) != 0);
+ sprites[1].priority = ((val & 0x02) != 0);
+ sprites[2].priority = ((val & 0x04) != 0);
+ sprites[3].priority = ((val & 0x08) != 0);
+ sprites[4].priority = ((val & 0x10) != 0);
+ sprites[5].priority = ((val & 0x20) != 0);
+ sprites[6].priority = ((val & 0x40) != 0);
+ sprites[7].priority = ((val & 0x80) != 0);
+ break;
+ case 0x1C:
+ sprites[0].multicolor = ((val & 0x01) != 0);
+ sprites[1].multicolor = ((val & 0x02) != 0);
+ sprites[2].multicolor = ((val & 0x04) != 0);
+ sprites[3].multicolor = ((val & 0x08) != 0);
+ sprites[4].multicolor = ((val & 0x10) != 0);
+ sprites[5].multicolor = ((val & 0x20) != 0);
+ sprites[6].multicolor = ((val & 0x40) != 0);
+ sprites[7].multicolor = ((val & 0x80) != 0);
+ break;
+ case 0x1D:
+ sprites[0].xExpand = ((val & 0x01) != 0);
+ sprites[1].xExpand = ((val & 0x02) != 0);
+ sprites[2].xExpand = ((val & 0x04) != 0);
+ sprites[3].xExpand = ((val & 0x08) != 0);
+ sprites[4].xExpand = ((val & 0x10) != 0);
+ sprites[5].xExpand = ((val & 0x20) != 0);
+ sprites[6].xExpand = ((val & 0x40) != 0);
+ sprites[7].xExpand = ((val & 0x80) != 0);
+ break;
+ case 0x1E:
+ sprites[0].collideSprite = ((val & 0x01) != 0);
+ sprites[1].collideSprite = ((val & 0x02) != 0);
+ sprites[2].collideSprite = ((val & 0x04) != 0);
+ sprites[3].collideSprite = ((val & 0x08) != 0);
+ sprites[4].collideSprite = ((val & 0x10) != 0);
+ sprites[5].collideSprite = ((val & 0x20) != 0);
+ sprites[6].collideSprite = ((val & 0x40) != 0);
+ sprites[7].collideSprite = ((val & 0x80) != 0);
+ break;
+ case 0x1F:
+ sprites[0].collideData = ((val & 0x01) != 0);
+ sprites[1].collideData = ((val & 0x02) != 0);
+ sprites[2].collideData = ((val & 0x04) != 0);
+ sprites[3].collideData = ((val & 0x08) != 0);
+ sprites[4].collideData = ((val & 0x10) != 0);
+ sprites[5].collideData = ((val & 0x20) != 0);
+ sprites[6].collideData = ((val & 0x40) != 0);
+ sprites[7].collideData = ((val & 0x80) != 0);
+ break;
+ case 0x20:
+ borderColor = (val & 0xF);
+ break;
+ case 0x21:
+ backgroundColor0 = (val & 0xF);
+ break;
+ case 0x22:
+ backgroundColor1 = (val & 0xF);
+ break;
+ case 0x23:
+ backgroundColor2 = (val & 0xF);
+ break;
+ case 0x24:
+ backgroundColor3 = (val & 0xF);
+ break;
+ case 0x25:
+ spriteMulticolor0 = (val & 0xF);
+ break;
+ case 0x26:
+ spriteMulticolor1 = (val & 0xF);
+ break;
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ sprites[addr - 0x27].color = (val & 0xF);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Render.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Render.cs
new file mode 100644
index 0000000000..8d767a5539
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Render.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64.MOS
+{
+ public abstract partial class Vic
+ {
+ private void Render()
+ {
+
+ {
+ renderEnabled = bufRect.Contains(bufPoint);
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (borderCheckLEnable && rasterX == borderL)
+ {
+ if (rasterLine == borderB)
+ borderOnVertical = true;
+ if (rasterLine == borderT && displayEnable)
+ borderOnVertical = false;
+ if (!borderOnVertical)
+ borderOnMain = false;
+ }
+ if (borderCheckREnable && rasterX == borderR)
+ {
+ borderOnMain = true;
+ }
+
+ // recall pixel from buffer
+ pixel = pixelBuffer[pixelBufferIndex];
+
+ // plot pixel if within viewing area
+ if (renderEnabled)
+ {
+ buf[bufOffset] = palette[pixel];
+ bufOffset++;
+ if (bufOffset == bufLength)
+ bufOffset = 0;
+ }
+ bufPoint.X++;
+ if (bufPoint.X == bufWidth)
+ {
+ bufPoint.X = 0;
+ bufPoint.Y++;
+ if (bufPoint.Y == bufHeight)
+ bufPoint.Y = 0;
+ }
+
+ // put the pixel from the background buffer into the main buffer
+ pixel = pixelBackgroundBuffer[pixelBackgroundBufferIndex];
+
+ // render sprite
+ int pixelOwner = 8;
+ for (int j = 0; j < 8; j++)
+ {
+ int sprData;
+ int sprPixel = pixel;
+
+ Sprite spr = sprites[j];
+
+ if (spr.x == rasterX)
+ spr.shiftEnable = true;
+
+ if (spr.shiftEnable)
+ {
+ if (spr.multicolor)
+ {
+ sprData = (spr.sr & 0xC00000) >> 22;
+ if (spr.multicolorCrunch && spr.xCrunch)
+ spr.sr <<= 2;
+ spr.multicolorCrunch ^= spr.xCrunch;
+ }
+ else
+ {
+ sprData = (spr.sr & 0x800000) >> 22;
+ if (spr.xCrunch)
+ spr.sr <<= 1;
+ }
+ spr.xCrunch ^= spr.xExpand;
+ switch (sprData)
+ {
+ case 1: sprPixel = spriteMulticolor0; break;
+ case 2: sprPixel = spr.color; break;
+ case 3: sprPixel = spriteMulticolor1; break;
+ }
+ if (sprData != 0)
+ {
+ // sprite-sprite collision
+ if (pixelOwner >= 8)
+ {
+ if (!spr.priority || (pixelDataBuffer[pixelBackgroundBufferIndex] < 0x2))
+ pixel = sprPixel;
+ pixelOwner = j;
+ }
+ else
+ {
+ if (!borderOnVertical)
+ {
+ spr.collideSprite = true;
+ sprites[pixelOwner].collideSprite = true;
+ }
+ }
+
+ // sprite-data collision
+ if (!borderOnVertical && (pixelDataBuffer[pixelBackgroundBufferIndex] >= 0x2))
+ {
+ spr.collideData = true;
+ }
+ }
+ if (spr.sr == 0)
+ spr.shiftEnable = false; //optimization
+ }
+ }
+
+ // border doesn't work with the background buffer
+ if (borderOnMain || borderOnVertical)
+ pixel = borderColor;
+
+ // store pixel in buffer
+ pixelBuffer[pixelBufferIndex] = pixel;
+
+ // fill shift register
+ if (xOffset == xScroll)
+ {
+ if (displayIndex < 40 && !idle)
+ {
+ displayC = bufferC[displayIndex];
+ sr |= bufferG[displayIndex];
+ }
+ bitmapColumn = 0;
+ }
+
+ if (!extraColorMode && !bitmapMode & !multicolorMode)
+ {
+ // 000
+ pixelData = (sr & 0x80) >> 6;
+ sr <<= 1;
+ pixel = (pixelData != 0) ? displayC >> 8 : backgroundColor0;
+ }
+ else if (!extraColorMode && !bitmapMode & multicolorMode)
+ {
+ // 001
+ if ((displayC & 0x800) != 0)
+ {
+ // multicolor 001
+ pixelData = (sr & 0xC0) >> 6;
+ if ((bitmapColumn & 1) != 0)
+ sr <<= 2;
+ switch (pixelData)
+ {
+ case 0x00: pixel = backgroundColor0; break;
+ case 0x01: pixel = backgroundColor1; break;
+ case 0x02: pixel = backgroundColor2; break;
+ default: pixel = (displayC & 0x700) >> 8; break;
+ }
+ }
+ else
+ {
+ // standard 001
+ pixelData = (sr & 0x80) >> 6;
+ sr <<= 1;
+ pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0;
+ }
+ }
+ else if (!extraColorMode && bitmapMode & !multicolorMode)
+ {
+ // 010
+ pixelData = (sr & 0x80) >> 6;
+ sr <<= 1;
+ pixel = (pixelData != 0) ? ((displayC >> 4) & 0xF) : (displayC & 0xF);
+ }
+ else if (!extraColorMode && bitmapMode & multicolorMode)
+ {
+ // 011
+ pixelData = (sr & 0xC0) >> 6;
+ if ((bitmapColumn & 1) != 0)
+ sr <<= 2;
+ switch (pixelData)
+ {
+ case 0x00: pixel = backgroundColor0; break;
+ case 0x01: pixel = (displayC >> 4) & 0xF; break;
+ case 0x02: pixel = displayC & 0xF; break;
+ default: pixel = (displayC >> 8) & 0xF; break;
+ }
+ }
+ else if (extraColorMode && !bitmapMode & !multicolorMode)
+ {
+ // 100
+ pixelData = (sr & 0x80) >> 6;
+ sr <<= 1;
+ if (pixelData != 0)
+ {
+ pixel = displayC >> 8;
+ }
+ else
+ {
+ switch ((displayC >> 6) & 0x3)
+ {
+ case 0x00: pixel = backgroundColor0; break;
+ case 0x01: pixel = backgroundColor1; break;
+ case 0x02: pixel = backgroundColor2; break;
+ default: pixel = backgroundColor3; break;
+ }
+ }
+ }
+ else if (extraColorMode && !bitmapMode & multicolorMode)
+ {
+ // 101
+ pixelData = 0;
+ pixel = 0;
+ }
+ else if (extraColorMode && bitmapMode & !multicolorMode)
+ {
+ // 110
+ pixelData = 0;
+ pixel = 0;
+ }
+ else
+ {
+ // 111
+ pixelData = 0;
+ pixel = 0;
+ }
+
+ // put the rendered pixel into the background buffer
+ pixelDataBuffer[pixelBackgroundBufferIndex] = pixelData;
+ pixelBackgroundBuffer[pixelBackgroundBufferIndex] = pixel;
+ pixelBackgroundBufferIndex++;
+ if (pixelBackgroundBufferIndex == pixelBackgroundBufferDelay)
+ pixelBackgroundBufferIndex = 0;
+
+ // advance pixel buffer
+ pixelBufferIndex++;
+ if (pixelBufferIndex == pixelBufferDelay)
+ pixelBufferIndex = 0;
+
+ rasterX++;
+ xOffset++;
+ bitmapColumn++;
+ }
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Sprite.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Sprite.cs
new file mode 100644
index 0000000000..6d25edfb90
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.Sprite.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64.MOS
+{
+ public abstract partial class Vic
+ {
+ private class Sprite
+ {
+ public bool collideData;
+ public bool collideSprite;
+ public int color;
+ public bool display;
+ public bool dma;
+ public bool enable;
+ public int mc;
+ public int mcbase;
+ public bool multicolor;
+ public bool multicolorCrunch;
+ public int pointer;
+ public bool priority;
+ public bool shiftEnable;
+ public int sr;
+ public int x;
+ public bool xCrunch;
+ public bool xExpand;
+ public int y;
+ public bool yCrunch;
+ public bool yExpand;
+
+ public void HardReset()
+ {
+ collideData = false;
+ collideSprite = false;
+ color = 0;
+ display = false;
+ dma = false;
+ enable = false;
+ mc = 0;
+ mcbase = 0;
+ multicolor = false;
+ multicolorCrunch = false;
+ pointer = 0;
+ priority = false;
+ shiftEnable = false;
+ sr = 0;
+ x = 0;
+ xCrunch = false;
+ xExpand = false;
+ y = 0;
+ yCrunch = false;
+ yExpand = false;
+ }
+
+ public void SyncState(Serializer ser)
+ {
+ ser.Sync("collideData", ref collideData);
+ ser.Sync("collideSprite", ref collideSprite);
+ ser.Sync("color", ref color);
+ ser.Sync("display", ref display);
+ ser.Sync("dma", ref dma);
+ ser.Sync("enable", ref enable);
+ ser.Sync("mc", ref mc);
+ ser.Sync("mcbase", ref mcbase);
+ ser.Sync("multicolor", ref multicolor);
+ ser.Sync("multicolorCrunch", ref multicolorCrunch);
+ ser.Sync("pointer", ref pointer);
+ ser.Sync("priority", ref priority);
+ ser.Sync("shiftEnable", ref shiftEnable);
+ ser.Sync("sr", ref sr);
+ ser.Sync("x", ref x);
+ ser.Sync("xCrunch", ref xCrunch);
+ ser.Sync("xExpand", ref xExpand);
+ ser.Sync("y", ref y);
+ ser.Sync("yCrunch", ref yCrunch);
+ ser.Sync("yExpand", ref yExpand);
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs
index a9f8ab0a4d..4df5a00da1 100644
--- a/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/MOS/Vic.cs
@@ -7,92 +7,13 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// ------------------------------------
- private class Sprite
- {
- public bool collideData;
- public bool collideSprite;
- public int color;
- public bool display;
- public bool dma;
- public bool enable;
- public int mc;
- public int mcbase;
- public bool multicolor;
- public bool multicolorCrunch;
- public int pointer;
- public bool priority;
- public bool shiftEnable;
- public int sr;
- public int x;
- public bool xCrunch;
- public bool xExpand;
- public int y;
- public bool yCrunch;
- public bool yExpand;
-
- public void HardReset()
- {
- collideData = false;
- collideSprite = false;
- color = 0;
- display = false;
- dma = false;
- enable = false;
- mc = 0;
- mcbase = 0;
- multicolor = false;
- multicolorCrunch = false;
- pointer = 0;
- priority = false;
- shiftEnable = false;
- sr = 0;
- x = 0;
- xCrunch = false;
- xExpand = false;
- y = 0;
- yCrunch = false;
- yExpand = false;
- }
-
- public void SyncState(Serializer ser)
- {
- ser.Sync("collideData", ref collideData);
- ser.Sync("collideSprite", ref collideSprite);
- ser.Sync("color", ref color);
- ser.Sync("display", ref display);
- ser.Sync("dma", ref dma);
- ser.Sync("enable", ref enable);
- ser.Sync("mc", ref mc);
- ser.Sync("mcbase", ref mcbase);
- ser.Sync("multicolor", ref multicolor);
- ser.Sync("multicolorCrunch", ref multicolorCrunch);
- ser.Sync("pointer", ref pointer);
- ser.Sync("priority", ref priority);
- ser.Sync("shiftEnable", ref shiftEnable);
- ser.Sync("sr", ref sr);
- ser.Sync("x", ref x);
- ser.Sync("xCrunch", ref xCrunch);
- ser.Sync("xExpand", ref xExpand);
- ser.Sync("y", ref y);
- ser.Sync("yCrunch", ref yCrunch);
- ser.Sync("yExpand", ref yExpand);
- }
- }
- private Sprite[] sprites;
-
- private int backgroundColor0;
- private int backgroundColor1;
- private int backgroundColor2;
- private int backgroundColor3;
private int baCount;
private bool badline;
private bool badlineEnable;
private int bitmapColumn;
- private bool bitmapMode;
private int borderB;
private bool borderCheckLEnable;
private bool borderCheckREnable;
- private int borderColor;
private int borderL;
private bool borderOnMain;
private bool borderOnVertical;
@@ -100,37 +21,15 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private int borderT;
private int[] bufferC;
private int[] bufferG;
- private bool columnSelect;
private int cycle;
private int cycleIndex;
private int dataC;
private int dataG;
private bool debugScreen;
private int displayC;
- private bool displayEnable;
private int displayIndex;
- private bool enableIntLightPen;
- private bool enableIntRaster;
- private bool enableIntSpriteCollision;
- private bool enableIntSpriteDataCollision;
- private bool extraColorMode;
private bool idle;
- private bool intLightPen;
- private bool intRaster;
- private bool intSpriteCollision;
- private bool intSpriteDataCollision;
private int lastRasterLine;
- private int lightPenX;
- private int lightPenY;
- private bool multicolorMode;
- private int parseaddr;
- private int parsecycleBAsprite0;
- private int parsecycleBAsprite1;
- private int parsecycleBAsprite2;
- private int parsecycleFetchSpriteIndex;
- private int parsefetch;
- private int parseba;
- private int parseact;
private int pixel;
private int[] pixelBackgroundBuffer;
private int pixelBackgroundBufferDelay;
@@ -140,24 +39,14 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private int pixelBufferIndex;
private int pixelData;
private int[] pixelDataBuffer;
- private int pointerCB;
- private int pointerVM;
- private int rasterInterruptLine;
- private int rasterLine;
- private int rasterX;
private int rc;
private int refreshCounter;
private bool renderEnabled;
- private bool rowSelect;
- private int spriteMulticolor0;
- private int spriteMulticolor1;
private int sr;
private int vc;
private int vcbase;
private int vmli;
private int xOffset;
- private int xScroll;
- private int yScroll;
// ------------------------------------
@@ -443,459 +332,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
}
}
- private void ParseCycle()
- {
-
- {
- parseaddr = 0x3FFF;
- parsefetch = pipeline[1][cycleIndex];
- parseba = pipeline[2][cycleIndex];
- parseact = pipeline[3][cycleIndex];
-
- // apply X location
- rasterX = pipeline[0][cycleIndex];
-
- // perform fetch
- switch (parsefetch & 0xFF00)
- {
- case 0x0100:
- // fetch R
- refreshCounter = (refreshCounter - 1) & 0xFF;
- parseaddr = (0x3F00 | refreshCounter);
- ReadMemory(parseaddr);
- break;
- case 0x0200:
- // fetch C
- if (!idle)
- {
- if (badline)
- {
- parseaddr = ((pointerVM << 10) | vc);
- dataC = ReadMemory(parseaddr);
- dataC |= ((int)ReadColorRam(parseaddr) & 0xF) << 8;
- bufferC[vmli] = dataC;
- }
- else
- {
- dataC = bufferC[vmli];
- }
- }
- else
- {
- dataC = 0;
- bufferC[vmli] = dataC;
- }
- break;
- case 0x0300:
- // fetch G
- if (idle)
- parseaddr = 0x3FFF;
- else
- {
- if (bitmapMode)
- parseaddr = (rc | (vc << 3) | ((pointerCB & 0x4) << 11));
- else
- parseaddr = (rc | ((dataC & 0xFF) << 3) | (pointerCB << 11));
- }
- if (extraColorMode)
- parseaddr &= 0x39FF;
- dataG = ReadMemory(parseaddr);
- if (!idle)
- {
- bufferG[vmli] = dataG;
- vmli = (vmli + 1) & 0x3F;
- vc = (vc + 1) & 0x3FF;
- }
- break;
- case 0x0400:
- // fetch I
- parseaddr = (extraColorMode ? 0x39FF : 0x3FFF);
- dataG = ReadMemory(parseaddr);
- dataC = 0;
- break;
- case 0x0500:
- // no fetch
- break;
- default:
- parsecycleFetchSpriteIndex = (parsefetch & 0x7);
- switch (parsefetch & 0xF0)
- {
- case 0x00:
- // fetch P
- parseaddr = (0x3F8 | (pointerVM << 10) | parsecycleFetchSpriteIndex);
- sprites[parsecycleFetchSpriteIndex].pointer = ReadMemory(parseaddr);
- sprites[parsecycleFetchSpriteIndex].shiftEnable = false;
- break;
- case 0x10:
- case 0x20:
- case 0x30:
- // fetch S
- if (sprites[parsecycleFetchSpriteIndex].dma)
- {
- Sprite spr = sprites[parsecycleFetchSpriteIndex];
- parseaddr = (spr.mc | (spr.pointer << 6));
- spr.sr <<= 8;
- spr.sr |= ReadMemory(parseaddr);
- spr.mc++;
- }
- break;
- }
- break;
- }
-
- // perform BA flag manipulation
- switch (parseba)
- {
- case 0x0000:
- pinBA = true;
- break;
- case 0x1000:
- pinBA = !badline;
- break;
- default:
- parsecycleBAsprite0 = (parseba & 0x000F);
- parsecycleBAsprite1 = (parseba & 0x00F0) >> 4;
- parsecycleBAsprite2 = (parseba & 0x0F00) >> 8;
- if ((parsecycleBAsprite0 < 8 && sprites[parsecycleBAsprite0].dma) ||
- (parsecycleBAsprite1 < 8 && sprites[parsecycleBAsprite1].dma) ||
- (parsecycleBAsprite2 < 8 && sprites[parsecycleBAsprite2].dma))
- pinBA = false;
- else
- pinBA = true;
- break;
- }
-
- // perform actions
- borderCheckLEnable = true;
- borderCheckREnable = true;
-
- if ((parseact & pipelineChkSprChunch) != 0)
- {
- //for (int i = 0; i < 8; i++)
- foreach (Sprite spr in sprites)
- {
- //Sprite spr = sprites[i];
- if (spr.yCrunch)
- spr.mcbase += 2;
- spr.shiftEnable = false;
- spr.xCrunch = !spr.xExpand;
- spr.multicolorCrunch = !spr.multicolor;
- }
- }
- if ((parseact & pipelineChkSprDisp) != 0)
- {
- //for (int i = 0; i < 8; i++)
- foreach (Sprite spr in sprites)
- {
- //Sprite spr = sprites[i];
- spr.mc = spr.mcbase;
- if (spr.dma && spr.y == (rasterLine & 0xFF))
- {
- spr.display = true;
- }
- }
- }
- if ((parseact & pipelineChkSprDma) != 0)
- {
- //for (int i = 0; i < 8; i++)
- foreach (Sprite spr in sprites)
- {
- //Sprite spr = sprites[i];
- if (spr.enable && spr.y == (rasterLine & 0xFF) && !spr.dma)
- {
- spr.dma = true;
- spr.mcbase = 0;
- spr.yCrunch = !spr.yExpand;
- }
- }
- }
- if ((parseact & pipelineChkSprExp) != 0)
- {
- if (sprites[0].yExpand) sprites[0].yCrunch ^= true;
- if (sprites[1].yExpand) sprites[1].yCrunch ^= true;
- if (sprites[2].yExpand) sprites[2].yCrunch ^= true;
- if (sprites[3].yExpand) sprites[3].yCrunch ^= true;
- if (sprites[4].yExpand) sprites[4].yCrunch ^= true;
- if (sprites[5].yExpand) sprites[5].yCrunch ^= true;
- if (sprites[6].yExpand) sprites[6].yCrunch ^= true;
- if (sprites[7].yExpand) sprites[7].yCrunch ^= true;
- }
- if ((parseact & pipelineUpdateMcBase) != 0)
- {
- //for (int i = 0; i < 8; i++)
- foreach (Sprite spr in sprites)
- {
- //Sprite spr = sprites[i];
- if (spr.yCrunch)
- {
- spr.mcbase++;
- if (spr.mcbase == 63)
- {
- spr.dma = false;
- spr.display = false;
- }
- }
- }
- }
- if ((parseact & pipelineUpdateRc) != 0)
- {
- if (rc == 7)
- {
- idle = true;
- vcbase = vc;
- }
- if (!idle)
- rc = (rc + 1) & 0x7;
- }
- if ((parseact & pipelineUpdateVc) != 0)
- {
- vc = vcbase;
- vmli = 0;
- if (badline)
- rc = 0;
- }
-
- cycleIndex++;
- }
- }
-
- private void Render()
- {
-
- {
- renderEnabled = bufRect.Contains(bufPoint);
-
- for (int i = 0; i < 4; i++)
- {
- if (borderCheckLEnable && rasterX == borderL)
- {
- if (rasterLine == borderB)
- borderOnVertical = true;
- if (rasterLine == borderT && displayEnable)
- borderOnVertical = false;
- if (!borderOnVertical)
- borderOnMain = false;
- }
- if (borderCheckREnable && rasterX == borderR)
- {
- borderOnMain = true;
- }
-
- // recall pixel from buffer
- pixel = pixelBuffer[pixelBufferIndex];
-
- // plot pixel if within viewing area
- if (renderEnabled)
- {
- buf[bufOffset] = palette[pixel];
- bufOffset++;
- if (bufOffset == bufLength)
- bufOffset = 0;
- }
- bufPoint.X++;
- if (bufPoint.X == bufWidth)
- {
- bufPoint.X = 0;
- bufPoint.Y++;
- if (bufPoint.Y == bufHeight)
- bufPoint.Y = 0;
- }
-
- // put the pixel from the background buffer into the main buffer
- pixel = pixelBackgroundBuffer[pixelBackgroundBufferIndex];
-
- // render sprite
- int pixelOwner = 8;
- for (int j = 0; j < 8; j++)
- {
- int sprData;
- int sprPixel = pixel;
-
- Sprite spr = sprites[j];
-
- if (spr.x == rasterX)
- spr.shiftEnable = true;
-
- if (spr.shiftEnable)
- {
- if (spr.multicolor)
- {
- sprData = (spr.sr & 0xC00000) >> 22;
- if (spr.multicolorCrunch && spr.xCrunch)
- spr.sr <<= 2;
- spr.multicolorCrunch ^= spr.xCrunch;
- }
- else
- {
- sprData = (spr.sr & 0x800000) >> 22;
- if (spr.xCrunch)
- spr.sr <<= 1;
- }
- spr.xCrunch ^= spr.xExpand;
- switch (sprData)
- {
- case 1: sprPixel = spriteMulticolor0; break;
- case 2: sprPixel = spr.color; break;
- case 3: sprPixel = spriteMulticolor1; break;
- }
- if (sprData != 0)
- {
- // sprite-sprite collision
- if (pixelOwner >= 8)
- {
- if (!spr.priority || (pixelDataBuffer[pixelBackgroundBufferIndex] < 0x2))
- pixel = sprPixel;
- pixelOwner = j;
- }
- else
- {
- if (!borderOnVertical)
- {
- spr.collideSprite = true;
- sprites[pixelOwner].collideSprite = true;
- }
- }
-
- // sprite-data collision
- if (!borderOnVertical && (pixelDataBuffer[pixelBackgroundBufferIndex] >= 0x2))
- {
- spr.collideData = true;
- }
- }
- if (spr.sr == 0)
- spr.shiftEnable = false; //optimization
- }
- }
-
- // border doesn't work with the background buffer
- if (borderOnMain || borderOnVertical)
- pixel = borderColor;
-
- // store pixel in buffer
- pixelBuffer[pixelBufferIndex] = pixel;
-
- // fill shift register
- if (xOffset == xScroll)
- {
- if (displayIndex < 40 && !idle)
- {
- displayC = bufferC[displayIndex];
- sr |= bufferG[displayIndex];
- }
- bitmapColumn = 0;
- }
-
- if (!extraColorMode && !bitmapMode & !multicolorMode)
- {
- // 000
- pixelData = (sr & 0x80) >> 6;
- sr <<= 1;
- pixel = (pixelData != 0) ? displayC >> 8 : backgroundColor0;
- }
- else if (!extraColorMode && !bitmapMode & multicolorMode)
- {
- // 001
- if ((displayC & 0x800) != 0)
- {
- // multicolor 001
- pixelData = (sr & 0xC0) >> 6;
- if ((bitmapColumn & 1) != 0)
- sr <<= 2;
- switch (pixelData)
- {
- case 0x00: pixel = backgroundColor0; break;
- case 0x01: pixel = backgroundColor1; break;
- case 0x02: pixel = backgroundColor2; break;
- default: pixel = (displayC & 0x700) >> 8; break;
- }
- }
- else
- {
- // standard 001
- pixelData = (sr & 0x80) >> 6;
- sr <<= 1;
- pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0;
- }
- }
- else if (!extraColorMode && bitmapMode & !multicolorMode)
- {
- // 010
- pixelData = (sr & 0x80) >> 6;
- sr <<= 1;
- pixel = (pixelData != 0) ? ((displayC >> 4) & 0xF) : (displayC & 0xF);
- }
- else if (!extraColorMode && bitmapMode & multicolorMode)
- {
- // 011
- pixelData = (sr & 0xC0) >> 6;
- if ((bitmapColumn & 1) != 0)
- sr <<= 2;
- switch (pixelData)
- {
- case 0x00: pixel = backgroundColor0; break;
- case 0x01: pixel = (displayC >> 4) & 0xF; break;
- case 0x02: pixel = displayC & 0xF; break;
- default: pixel = (displayC >> 8) & 0xF; break;
- }
- }
- else if (extraColorMode && !bitmapMode & !multicolorMode)
- {
- // 100
- pixelData = (sr & 0x80) >> 6;
- sr <<= 1;
- if (pixelData != 0)
- {
- pixel = displayC >> 8;
- }
- else
- {
- switch ((displayC >> 6) & 0x3)
- {
- case 0x00: pixel = backgroundColor0; break;
- case 0x01: pixel = backgroundColor1; break;
- case 0x02: pixel = backgroundColor2; break;
- default: pixel = backgroundColor3; break;
- }
- }
- }
- else if (extraColorMode && !bitmapMode & multicolorMode)
- {
- // 101
- pixelData = 0;
- pixel = 0;
- }
- else if (extraColorMode && bitmapMode & !multicolorMode)
- {
- // 110
- pixelData = 0;
- pixel = 0;
- }
- else
- {
- // 111
- pixelData = 0;
- pixel = 0;
- }
-
- // put the rendered pixel into the background buffer
- pixelDataBuffer[pixelBackgroundBufferIndex] = pixelData;
- pixelBackgroundBuffer[pixelBackgroundBufferIndex] = pixel;
- pixelBackgroundBufferIndex++;
- if (pixelBackgroundBufferIndex == pixelBackgroundBufferDelay)
- pixelBackgroundBufferIndex = 0;
-
- // advance pixel buffer
- pixelBufferIndex++;
- if (pixelBufferIndex == pixelBufferDelay)
- pixelBufferIndex = 0;
-
- rasterX++;
- xOffset++;
- bitmapColumn++;
- }
- }
- }
-
// ------------------------------------
public bool ReadAECBuffer() { return pinAEC; }
@@ -922,492 +358,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
// ------------------------------------
- public byte Peek(int addr)
- {
- return ReadRegister((addr & 0x3F));
- }
-
- public void Poke(int addr, byte val)
- {
- WriteRegister((addr & 0x3F), val);
- }
-
- public byte Read(int addr)
- {
- byte result;
- addr &= 0x3F;
-
- switch (addr)
- {
- case 0x1E:
- case 0x1F:
- // reading clears these
- result = ReadRegister(addr);
- WriteRegister(addr, 0);
- break;
- default:
- result = ReadRegister((addr & 0x3F));
- break;
- }
- return result;
- }
-
- private byte ReadRegister(int addr)
- {
- byte result = 0xFF; //unused bit value
-
- switch (addr)
- {
- case 0x00:
- case 0x02:
- case 0x04:
- case 0x06:
- case 0x08:
- case 0x0A:
- case 0x0C:
- case 0x0E:
- result = (byte)(sprites[addr >> 1].x & 0xFF);
- break;
- case 0x01:
- case 0x03:
- case 0x05:
- case 0x07:
- case 0x09:
- case 0x0B:
- case 0x0D:
- case 0x0F:
- result = (byte)(sprites[addr >> 1].y & 0xFF);
- break;
- case 0x10:
- result = (byte)(
- ((sprites[0].x >> 8) & 0x01) |
- ((sprites[1].x >> 7) & 0x02) |
- ((sprites[2].x >> 6) & 0x04) |
- ((sprites[3].x >> 5) & 0x08) |
- ((sprites[4].x >> 4) & 0x10) |
- ((sprites[5].x >> 3) & 0x20) |
- ((sprites[6].x >> 2) & 0x40) |
- ((sprites[7].x >> 1) & 0x80)
- );
- break;
- case 0x11:
- result = (byte)(
- (yScroll & 0x7) |
- (rowSelect ? 0x08 : 0x00) |
- (displayEnable ? 0x10 : 0x00) |
- (bitmapMode ? 0x20 : 0x00) |
- (extraColorMode ? 0x40 : 0x00) |
- ((rasterLine & 0x100) >> 1)
- );
- break;
- case 0x12:
- result = (byte)(rasterLine & 0xFF);
- break;
- case 0x13:
- result = (byte)(lightPenX & 0xFF);
- break;
- case 0x14:
- result = (byte)(lightPenY & 0xFF);
- break;
- case 0x15:
- result = (byte)(
- (sprites[0].enable ? 0x01 : 0x00) |
- (sprites[1].enable ? 0x02 : 0x00) |
- (sprites[2].enable ? 0x04 : 0x00) |
- (sprites[3].enable ? 0x08 : 0x00) |
- (sprites[4].enable ? 0x10 : 0x00) |
- (sprites[5].enable ? 0x20 : 0x00) |
- (sprites[6].enable ? 0x40 : 0x00) |
- (sprites[7].enable ? 0x80 : 0x00)
- );
- break;
- case 0x16:
- result &= 0xC0;
- result |= (byte)(
- (xScroll & 0x7) |
- (columnSelect ? 0x08 : 0x00) |
- (multicolorMode ? 0x10 : 0x00)
- );
- break;
- case 0x17:
- result = (byte)(
- (sprites[0].yExpand ? 0x01 : 0x00) |
- (sprites[1].yExpand ? 0x02 : 0x00) |
- (sprites[2].yExpand ? 0x04 : 0x00) |
- (sprites[3].yExpand ? 0x08 : 0x00) |
- (sprites[4].yExpand ? 0x10 : 0x00) |
- (sprites[5].yExpand ? 0x20 : 0x00) |
- (sprites[6].yExpand ? 0x40 : 0x00) |
- (sprites[7].yExpand ? 0x80 : 0x00)
- );
- break;
- case 0x18:
- result &= 0x01;
- result |= (byte)(
- ((pointerVM & 0xF) << 4) |
- ((pointerCB & 0x7) << 1)
- );
- break;
- case 0x19:
- result &= 0x70;
- result |= (byte)(
- (intRaster ? 0x01 : 0x00) |
- (intSpriteDataCollision ? 0x02 : 0x00) |
- (intSpriteCollision ? 0x04 : 0x00) |
- (intLightPen ? 0x08 : 0x00) |
- (pinIRQ ? 0x00 : 0x80)
- );
- break;
- case 0x1A:
- result &= 0xF0;
- result |= (byte)(
- (enableIntRaster ? 0x01 : 0x00) |
- (enableIntSpriteDataCollision ? 0x02 : 0x00) |
- (enableIntSpriteCollision ? 0x04 : 0x00) |
- (enableIntLightPen ? 0x08 : 0x00)
- );
- break;
- case 0x1B:
- result = (byte)(
- (sprites[0].priority ? 0x01 : 0x00) |
- (sprites[1].priority ? 0x02 : 0x00) |
- (sprites[2].priority ? 0x04 : 0x00) |
- (sprites[3].priority ? 0x08 : 0x00) |
- (sprites[4].priority ? 0x10 : 0x00) |
- (sprites[5].priority ? 0x20 : 0x00) |
- (sprites[6].priority ? 0x40 : 0x00) |
- (sprites[7].priority ? 0x80 : 0x00)
- );
- break;
- case 0x1C:
- result = (byte)(
- (sprites[0].multicolor ? 0x01 : 0x00) |
- (sprites[1].multicolor ? 0x02 : 0x00) |
- (sprites[2].multicolor ? 0x04 : 0x00) |
- (sprites[3].multicolor ? 0x08 : 0x00) |
- (sprites[4].multicolor ? 0x10 : 0x00) |
- (sprites[5].multicolor ? 0x20 : 0x00) |
- (sprites[6].multicolor ? 0x40 : 0x00) |
- (sprites[7].multicolor ? 0x80 : 0x00)
- );
- break;
- case 0x1D:
- result = (byte)(
- (sprites[0].xExpand ? 0x01 : 0x00) |
- (sprites[1].xExpand ? 0x02 : 0x00) |
- (sprites[2].xExpand ? 0x04 : 0x00) |
- (sprites[3].xExpand ? 0x08 : 0x00) |
- (sprites[4].xExpand ? 0x10 : 0x00) |
- (sprites[5].xExpand ? 0x20 : 0x00) |
- (sprites[6].xExpand ? 0x40 : 0x00) |
- (sprites[7].xExpand ? 0x80 : 0x00)
- );
- break;
- case 0x1E:
- result = (byte)(
- (sprites[0].collideSprite ? 0x01 : 0x00) |
- (sprites[1].collideSprite ? 0x02 : 0x00) |
- (sprites[2].collideSprite ? 0x04 : 0x00) |
- (sprites[3].collideSprite ? 0x08 : 0x00) |
- (sprites[4].collideSprite ? 0x10 : 0x00) |
- (sprites[5].collideSprite ? 0x20 : 0x00) |
- (sprites[6].collideSprite ? 0x40 : 0x00) |
- (sprites[7].collideSprite ? 0x80 : 0x00)
- );
- break;
- case 0x1F:
- result = (byte)(
- (sprites[0].collideData ? 0x01 : 0x00) |
- (sprites[1].collideData ? 0x02 : 0x00) |
- (sprites[2].collideData ? 0x04 : 0x00) |
- (sprites[3].collideData ? 0x08 : 0x00) |
- (sprites[4].collideData ? 0x10 : 0x00) |
- (sprites[5].collideData ? 0x20 : 0x00) |
- (sprites[6].collideData ? 0x40 : 0x00) |
- (sprites[7].collideData ? 0x80 : 0x00)
- );
- break;
- case 0x20:
- result &= 0xF0;
- result |= (byte)(borderColor & 0x0F);
- break;
- case 0x21:
- result &= 0xF0;
- result |= (byte)(backgroundColor0 & 0x0F);
- break;
- case 0x22:
- result &= 0xF0;
- result |= (byte)(backgroundColor1 & 0x0F);
- break;
- case 0x23:
- result &= 0xF0;
- result |= (byte)(backgroundColor2 & 0x0F);
- break;
- case 0x24:
- result &= 0xF0;
- result |= (byte)(backgroundColor3 & 0x0F);
- break;
- case 0x25:
- result &= 0xF0;
- result |= (byte)(spriteMulticolor0 & 0x0F);
- break;
- case 0x26:
- result &= 0xF0;
- result |= (byte)(spriteMulticolor1 & 0x0F);
- break;
- case 0x27:
- case 0x28:
- case 0x29:
- case 0x2A:
- case 0x2B:
- case 0x2C:
- case 0x2D:
- case 0x2E:
- result &= 0xF0;
- result |= (byte)(sprites[addr - 0x27].color & 0xF);
- break;
- default:
- // not connected
- break;
- }
-
- return result;
- }
-
- public void Write(int addr, byte val)
- {
- addr &= 0x3F;
- switch (addr)
- {
- case 0x19:
- // interrupts are cleared by writing a 1
- if ((val & 0x01) != 0)
- intRaster = false;
- if ((val & 0x02) != 0)
- intSpriteDataCollision = false;
- if ((val & 0x04) != 0)
- intSpriteCollision = false;
- if ((val & 0x08) != 0)
- intLightPen = false;
- UpdatePins();
- break;
- case 0x1A:
- WriteRegister(addr, val);
- break;
- case 0x1E:
- case 0x1F:
- // can't write to these
- break;
- case 0x2F:
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- case 0x38:
- case 0x39:
- case 0x3A:
- case 0x3B:
- case 0x3C:
- case 0x3D:
- case 0x3E:
- case 0x3F:
- // not connected
- break;
- default:
- WriteRegister(addr, val);
- break;
- }
- }
-
- private void WriteRegister(int addr, byte val)
- {
- switch (addr)
- {
- case 0x00:
- case 0x02:
- case 0x04:
- case 0x06:
- case 0x08:
- case 0x0A:
- case 0x0C:
- case 0x0E:
- sprites[addr >> 1].x &= 0x100;
- sprites[addr >> 1].x |= val;
- break;
- case 0x01:
- case 0x03:
- case 0x05:
- case 0x07:
- case 0x09:
- case 0x0B:
- case 0x0D:
- case 0x0F:
- sprites[addr >> 1].y = val;
- break;
- case 0x10:
- sprites[0].x = (sprites[0].x & 0xFF) | ((val & 0x01) << 8);
- sprites[1].x = (sprites[1].x & 0xFF) | ((val & 0x02) << 7);
- sprites[2].x = (sprites[2].x & 0xFF) | ((val & 0x04) << 6);
- sprites[3].x = (sprites[3].x & 0xFF) | ((val & 0x08) << 5);
- sprites[4].x = (sprites[4].x & 0xFF) | ((val & 0x10) << 4);
- sprites[5].x = (sprites[5].x & 0xFF) | ((val & 0x20) << 3);
- sprites[6].x = (sprites[6].x & 0xFF) | ((val & 0x40) << 2);
- sprites[7].x = (sprites[7].x & 0xFF) | ((val & 0x80) << 1);
- break;
- case 0x11:
- yScroll = (val & 0x07);
- rowSelect = ((val & 0x08) != 0);
- displayEnable = ((val & 0x10) != 0);
- bitmapMode = ((val & 0x20) != 0);
- extraColorMode = ((val & 0x40) != 0);
- rasterInterruptLine &= 0xFF;
- rasterInterruptLine |= (val & 0x80) << 1;
- UpdateBorder();
- break;
- case 0x12:
- rasterInterruptLine &= 0x100;
- rasterInterruptLine |= val;
- break;
- case 0x13:
- lightPenX = val;
- break;
- case 0x14:
- lightPenY = val;
- break;
- case 0x15:
- sprites[0].enable = ((val & 0x01) != 0);
- sprites[1].enable = ((val & 0x02) != 0);
- sprites[2].enable = ((val & 0x04) != 0);
- sprites[3].enable = ((val & 0x08) != 0);
- sprites[4].enable = ((val & 0x10) != 0);
- sprites[5].enable = ((val & 0x20) != 0);
- sprites[6].enable = ((val & 0x40) != 0);
- sprites[7].enable = ((val & 0x80) != 0);
- break;
- case 0x16:
- xScroll = (val & 0x07);
- columnSelect = ((val & 0x08) != 0);
- multicolorMode = ((val & 0x10) != 0);
- UpdateBorder();
- break;
- case 0x17:
- sprites[0].yExpand = ((val & 0x01) != 0);
- sprites[1].yExpand = ((val & 0x02) != 0);
- sprites[2].yExpand = ((val & 0x04) != 0);
- sprites[3].yExpand = ((val & 0x08) != 0);
- sprites[4].yExpand = ((val & 0x10) != 0);
- sprites[5].yExpand = ((val & 0x20) != 0);
- sprites[6].yExpand = ((val & 0x40) != 0);
- sprites[7].yExpand = ((val & 0x80) != 0);
- break;
- case 0x18:
- pointerVM = ((val >> 4) & 0xF);
- pointerCB = ((val >> 1) & 0x7);
- break;
- case 0x19:
- intRaster = ((val & 0x01) != 0);
- intSpriteDataCollision = ((val & 0x02) != 0);
- intSpriteCollision = ((val & 0x04) != 0);
- intLightPen = ((val & 0x08) != 0);
- UpdatePins();
- break;
- case 0x1A:
- enableIntRaster = ((val & 0x01) != 0);
- enableIntSpriteDataCollision = ((val & 0x02) != 0);
- enableIntSpriteCollision = ((val & 0x04) != 0);
- enableIntLightPen = ((val & 0x08) != 0);
- UpdatePins();
- break;
- case 0x1B:
- sprites[0].priority = ((val & 0x01) != 0);
- sprites[1].priority = ((val & 0x02) != 0);
- sprites[2].priority = ((val & 0x04) != 0);
- sprites[3].priority = ((val & 0x08) != 0);
- sprites[4].priority = ((val & 0x10) != 0);
- sprites[5].priority = ((val & 0x20) != 0);
- sprites[6].priority = ((val & 0x40) != 0);
- sprites[7].priority = ((val & 0x80) != 0);
- break;
- case 0x1C:
- sprites[0].multicolor = ((val & 0x01) != 0);
- sprites[1].multicolor = ((val & 0x02) != 0);
- sprites[2].multicolor = ((val & 0x04) != 0);
- sprites[3].multicolor = ((val & 0x08) != 0);
- sprites[4].multicolor = ((val & 0x10) != 0);
- sprites[5].multicolor = ((val & 0x20) != 0);
- sprites[6].multicolor = ((val & 0x40) != 0);
- sprites[7].multicolor = ((val & 0x80) != 0);
- break;
- case 0x1D:
- sprites[0].xExpand = ((val & 0x01) != 0);
- sprites[1].xExpand = ((val & 0x02) != 0);
- sprites[2].xExpand = ((val & 0x04) != 0);
- sprites[3].xExpand = ((val & 0x08) != 0);
- sprites[4].xExpand = ((val & 0x10) != 0);
- sprites[5].xExpand = ((val & 0x20) != 0);
- sprites[6].xExpand = ((val & 0x40) != 0);
- sprites[7].xExpand = ((val & 0x80) != 0);
- break;
- case 0x1E:
- sprites[0].collideSprite = ((val & 0x01) != 0);
- sprites[1].collideSprite = ((val & 0x02) != 0);
- sprites[2].collideSprite = ((val & 0x04) != 0);
- sprites[3].collideSprite = ((val & 0x08) != 0);
- sprites[4].collideSprite = ((val & 0x10) != 0);
- sprites[5].collideSprite = ((val & 0x20) != 0);
- sprites[6].collideSprite = ((val & 0x40) != 0);
- sprites[7].collideSprite = ((val & 0x80) != 0);
- break;
- case 0x1F:
- sprites[0].collideData = ((val & 0x01) != 0);
- sprites[1].collideData = ((val & 0x02) != 0);
- sprites[2].collideData = ((val & 0x04) != 0);
- sprites[3].collideData = ((val & 0x08) != 0);
- sprites[4].collideData = ((val & 0x10) != 0);
- sprites[5].collideData = ((val & 0x20) != 0);
- sprites[6].collideData = ((val & 0x40) != 0);
- sprites[7].collideData = ((val & 0x80) != 0);
- break;
- case 0x20:
- borderColor = (val & 0xF);
- break;
- case 0x21:
- backgroundColor0 = (val & 0xF);
- break;
- case 0x22:
- backgroundColor1 = (val & 0xF);
- break;
- case 0x23:
- backgroundColor2 = (val & 0xF);
- break;
- case 0x24:
- backgroundColor3 = (val & 0xF);
- break;
- case 0x25:
- spriteMulticolor0 = (val & 0xF);
- break;
- case 0x26:
- spriteMulticolor1 = (val & 0xF);
- break;
- case 0x27:
- case 0x28:
- case 0x29:
- case 0x2A:
- case 0x2B:
- case 0x2C:
- case 0x2D:
- case 0x2E:
- sprites[addr - 0x27].color = (val & 0xF);
- break;
- default:
- break;
- }
- }
-
// --------------------------
public void SyncState(Serializer ser)