Video chip timing in the old core now builds its timing tables dynamically instead of having them hardcoded- should greatly reduce human error. The algorithm should cover every single revision of VIC.

This commit is contained in:
saxxonpike 2013-08-24 15:21:51 +00:00
parent 1400c84fdd
commit 228fa3869f
12 changed files with 377 additions and 530 deletions

View File

@ -163,6 +163,7 @@
<Compile Include="Computers\Commodore64\MOS\Vic.Render.cs" /> <Compile Include="Computers\Commodore64\MOS\Vic.Render.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.Sprite.cs" /> <Compile Include="Computers\Commodore64\MOS\Vic.Sprite.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.State.cs" /> <Compile Include="Computers\Commodore64\MOS\Vic.State.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.TimingBuilder.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.VideoProvider.cs" /> <Compile Include="Computers\Commodore64\MOS\Vic.VideoProvider.cs" />
<Compile Include="Computers\Commodore64\Sync.cs" /> <Compile Include="Computers\Commodore64\Sync.cs" />
<Compile Include="Computers\Commodore64\Tape\VIC1530.cs" /> <Compile Include="Computers\Commodore64\Tape\VIC1530.cs" />

View File

@ -51,8 +51,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
sid = new MOS6581(44100, initRegion); sid = new MOS6581(44100, initRegion);
switch (initRegion) switch (initRegion)
{ {
case Region.NTSC: vic = new MOS6567(); break; case Region.NTSC: vic = MOS6567.Create(); break;
case Region.PAL: vic = new MOS6569(); break; case Region.PAL: vic = MOS6569.Create(); break;
} }
userPort = new UserPort(); userPort = new UserPort();
} }

View File

@ -1,13 +1,12 @@
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
// vic ntsc // vic ntsc
public class MOS6567 : Vic static public class MOS6567
{ {
static protected int[][] pipeline = new int[5][]; static int[][] pipeline = new int[5][];
static public Vic Create()
public MOS6567() {
: base(65, 263, pipeline, 14318181 / 14) return new Vic(65, 263, pipeline, 14318181 / 14);
{ }
}
} }
} }

View File

@ -1,244 +1,17 @@
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
// vic pal // vic pal
public class MOS6569 : Vic public class MOS6569
{ {
static protected int[][] pipeline = new int[][] static int[] timing = Vic.TimingBuilder_XRaster(0x194, 0x1F8, 0x1F8, -1, -1);
{ static int[] fetch = Vic.TimingBuilder_Fetch(timing, 0x164);
new int[] // xposition static int[] ba = Vic.TimingBuilder_BA(fetch);
{
0x0194, 0x0198,
0x019C, 0x01A0,
0x01A4, 0x01A8,
0x01AC, 0x01B0,
0x01B4, 0x01B8,
0x01BC, 0x01C0, static int[][] pipeline = new int[][]
0x01C4, 0x01C8, {
0x01CC, 0x01D0, timing,
0x01D4, 0x01D8, fetch,
0x01DC, 0x01E0, ba,
0x01E4, 0x01E8,
0x01EC, 0x01F0,
0x01F4, 0x0000,
0x0004, 0x0008,
0x000C, 0x0010,
0x0014, 0x0018,
0x001C, 0x0020,
0x0024, 0x0028,
0x002C, 0x0030,
0x0034, 0x0038,
0x003C, 0x0040,
0x0044, 0x0048,
0x004C, 0x0050,
0x0054, 0x0058,
0x005C, 0x0060,
0x0064, 0x0068,
0x006C, 0x0070,
0x0074, 0x0078,
0x007C, 0x0080,
0x0084, 0x0088,
0x008C, 0x0090,
0x0094, 0x0098,
0x009C, 0x00A0,
0x00A4, 0x00A8,
0x00AC, 0x00B0,
0x00B4, 0x00B8,
0x00BC, 0x00C0,
0x00C4, 0x00C8,
0x00CC, 0x00D0,
0x00D4, 0x00D8,
0x00DC, 0x00E0,
0x00E4, 0x00E8,
0x00EC, 0x00F0,
0x00F4, 0x00F8,
0x00FC, 0x0100,
0x0104, 0x0108,
0x010C, 0x0110,
0x0114, 0x0118,
0x011C, 0x0120,
0x0124, 0x0128,
0x012C, 0x0130,
0x0134, 0x0138,
0x013C, 0x0140,
0x0144, 0x0148,
0x014C, 0x0150,
0x0154, 0x0158,
0x015C, 0x0160,
0x0164, 0x0168,
0x016C, 0x0170,
0x0174, 0x0178,
0x017C, 0x0180,
0x0184, 0x0188,
0x018C, 0x0190
},
new int[] // fetch (100=ref 200=c 300=g 400=i 500=none)
{
0x0003, 0x0013,
0x0023, 0x0033,
0x0004, 0x0014,
0x0024, 0x0034,
0x0005, 0x0015,
0x0025, 0x0035,
0x0006, 0x0016,
0x0026, 0x0036,
0x0007, 0x0017,
0x0027, 0x0037,
0x0100, 0x0500,
0x0100, 0x0500,
0x0100, 0x0500,
0x0100, 0x0500,
0x0100, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0500,
0x0400, 0x0500,
0x0400, 0x0500,
0x0000, 0x0010,
0x0020, 0x0030,
0x0001, 0x0011,
0x0021, 0x0031,
0x0002, 0x0012,
0x0022, 0x0032
},
new int[] // BA
{
0x0843, 0x0843,
0x0543, 0x0543,
0x0548, 0x0548,
0x0546, 0x0546,
0x0586, 0x0586,
0x0576, 0x0576,
0x0876, 0x0876,
0x0876, 0x0876,
0x0878, 0x0878,
0x0878, 0x0878,
0x0000, 0x0000,
0x1000, 0x1000, // 12: badline ba start
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000, // 15: badline start
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x0880, 0x0880, // 55: sprites
0x0880, 0x0880,
0x0810, 0x0810,
0x0810, 0x0810,
0x0210, 0x0210,
0x0218, 0x0218,
0x0213, 0x0213,
0x0283, 0x0283,
0x0243, 0x0243
},
new int[] // actions new int[] // actions
{ {
0, 0, 0, 0,
@ -256,12 +29,12 @@
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, pipelineUpdateVc, 0, Vic.pipelineUpdateVc,
0, pipelineChkSprChunch, 0, Vic.pipelineChkSprChunch,
0, pipelineUpdateMcBase, 0, Vic.pipelineUpdateMcBase,
0, pipelineChkBrdL1, 0, Vic.pipelineChkBrdL1,
0, pipelineChkBrdL0, 0, Vic.pipelineChkBrdL0,
0, 0, 0, 0,
0, 0, 0, 0,
@ -305,11 +78,11 @@
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
pipelineChkSprDma, 0, Vic.pipelineChkSprDma, 0,
pipelineChkSprDma, pipelineChkBrdR0 | pipelineChkSprExp, Vic.pipelineChkSprDma, Vic.pipelineChkBrdR0 | Vic.pipelineChkSprExp,
0, pipelineChkBrdR1, 0, Vic.pipelineChkBrdR1,
pipelineChkSprDisp, pipelineUpdateRc, Vic.pipelineChkSprDisp, Vic.pipelineUpdateRc,
0, 0, 0, 0,
0, 0, 0, 0,
@ -319,9 +92,9 @@
} }
}; };
public MOS6569() static public Vic Create()
: base(63, 312, pipeline, 17734472 / 18) {
{ return new Vic(63, 312, pipeline, 17734472 / 18);
} }
} }
} }

View File

@ -5,22 +5,22 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic sealed public partial class Vic
{ {
protected const int baResetCounter = 6; public const int baResetCounter = 6;
protected const int pipelineUpdateVc = 1; public const int pipelineUpdateVc = 1;
protected const int pipelineChkSprChunch = 2; public const int pipelineChkSprChunch = 2;
protected const int pipelineUpdateMcBase = 4; public const int pipelineUpdateMcBase = 4;
protected const int pipelineChkBrdL1 = 8; public const int pipelineChkBrdL1 = 8;
protected const int pipelineChkBrdL0 = 16; public const int pipelineChkBrdL0 = 16;
protected const int pipelineChkSprDma = 32; public const int pipelineChkSprDma = 32;
protected const int pipelineChkBrdR0 = 64; public const int pipelineChkBrdR0 = 64;
protected const int pipelineChkSprExp = 128; public const int pipelineChkSprExp = 128;
protected const int pipelineChkBrdR1 = 256; public const int pipelineChkBrdR1 = 256;
protected const int pipelineChkSprDisp = 512; public const int pipelineChkSprDisp = 512;
protected const int pipelineUpdateRc = 1024; public const int pipelineUpdateRc = 1024;
protected const int rasterIrqLine0Cycle = 1; public const int rasterIrqLine0Cycle = 1;
protected const int rasterIrqLineXCycle = 0; public const int rasterIrqLineXCycle = 0;
protected int parseaddr; protected int parseaddr;
protected int parsecycleBAsprite0; protected int parsecycleBAsprite0;

View File

@ -5,7 +5,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic sealed public partial class Vic
{ {
public byte Peek(int addr) public byte Peek(int addr)

View File

@ -5,7 +5,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic sealed public partial class Vic
{ {
protected int ecmPixel; protected int ecmPixel;
protected int pixel; protected int pixel;
@ -33,222 +33,138 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private void Render() private void Render()
{ {
renderEnabled = bufRect.Contains(bufPoint);
for (int i = 0; i < 4; i++)
{ {
renderEnabled = bufRect.Contains(bufPoint); if (borderCheckLEnable && rasterX == borderL)
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
pixelOwner = 8;
for (int j = 0; j < 8; j++)
{
sprData = 0;
sprPixel = pixel;
Sprite spr = sprites[j];
if (spr.x == rasterX)
spr.shiftEnable = true;
if (spr.shiftEnable)
{ {
if (rasterLine == borderB) if (spr.multicolor)
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
pixelOwner = 8;
for (int j = 0; j < 8; j++)
{
sprData = 0;
sprPixel = pixel;
Sprite spr = sprites[j];
if (spr.x == rasterX)
spr.shiftEnable = true;
if (spr.shiftEnable)
{ {
if (spr.multicolor) sprData = (spr.sr & 0xC00000);
{ if (spr.multicolorCrunch && spr.xCrunch)
sprData = (spr.sr & 0xC00000); spr.sr <<= 2;
if (spr.multicolorCrunch && spr.xCrunch) spr.multicolorCrunch ^= spr.xCrunch;
spr.sr <<= 2;
spr.multicolorCrunch ^= spr.xCrunch;
}
else
{
sprData = (spr.sr & 0x800000);
if (spr.xCrunch)
spr.sr <<= 1;
}
spr.xCrunch ^= spr.xExpand;
if (sprData != 0)
{
if (sprData == 0x400000)
sprPixel = spriteMulticolor0;
else if (sprData == 0x800000)
sprPixel = spr.color;
else if (sprData == 0xC00000)
sprPixel = spriteMulticolor1;
// 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] == 0x80))
{
spr.collideData = true;
}
}
if (spr.sr == 0)
spr.shiftEnable = false; //optimization
} }
} else
// 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]; sprData = (spr.sr & 0x800000);
sr |= bufferG[displayIndex]; if (spr.xCrunch)
spr.sr <<= 1;
} }
bitmapColumn = 0; spr.xCrunch ^= spr.xExpand;
if (sprData != 0)
{
if (sprData == 0x400000)
sprPixel = spriteMulticolor0;
else if (sprData == 0x800000)
sprPixel = spr.color;
else if (sprData == 0xC00000)
sprPixel = spriteMulticolor1;
// sprite-sprite collision
if (pixelOwner >= 8)
{
if (!spr.priority || (pixelDataBuffer[pixelBackgroundBufferIndex] < 0x80))
pixel = sprPixel;
pixelOwner = j;
}
else
{
if (!borderOnVertical)
{
spr.collideSprite = true;
sprites[pixelOwner].collideSprite = true;
}
}
// sprite-data collision
if (!borderOnVertical && (pixelDataBuffer[pixelBackgroundBufferIndex] == 0x80))
{
spr.collideData = true;
}
}
if (spr.sr == 0)
spr.shiftEnable = false; //optimization
} }
}
#if true // border doesn't work with the background buffer
switch (videoMode) if (borderOnMain || borderOnVertical)
pixel = borderColor;
// store pixel in buffer
pixelBuffer[pixelBufferIndex] = pixel;
// fill shift register
if (xOffset == xScroll)
{
if (displayIndex < 40 && !idle)
{ {
case VicVideoMode.Mode000: displayC = bufferC[displayIndex];
pixelData = (sr & 0x80); sr |= bufferG[displayIndex];
sr <<= 1;
pixel = (pixelData != 0) ? displayC >> 8 : backgroundColor0;
break;
case VicVideoMode.Mode001:
if ((displayC & 0x800) != 0)
{
// multicolor 001
pixelData = (sr & 0xC0);
if ((bitmapColumn & 1) != 0)
sr <<= 2;
if (pixelData == 0x00)
pixel = backgroundColor0;
else if (pixelData == 0x40)
pixel = backgroundColor1;
else if (pixelData == 0x80)
pixel = backgroundColor2;
else
pixel = (displayC & 0x700) >> 8;
}
else
{
// standard 001
pixelData = (sr & 0x80);
sr <<= 1;
pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0;
}
break;
case VicVideoMode.Mode010:
pixelData = (sr & 0x80);
sr <<= 1;
pixel = (pixelData != 0) ? ((displayC >> 4) & 0xF) : (displayC & 0xF);
break;
case VicVideoMode.Mode011:
pixelData = (sr & 0xC0);
if ((bitmapColumn & 1) != 0)
sr <<= 2;
if (pixelData == 0x00)
pixel = backgroundColor0;
else if (pixelData == 0x40)
pixel = (displayC >> 4) & 0xF;
else if (pixelData == 0x80)
pixel = displayC & 0xF;
else
pixel = (displayC >> 8) & 0xF;
break;
case VicVideoMode.Mode100:
pixelData = (sr & 0x80);
sr <<= 1;
if (pixelData != 0)
{
pixel = displayC >> 8;
}
else
{
ecmPixel = (displayC) & 0xC0;
if (ecmPixel == 0x00)
pixel = backgroundColor0;
else if (ecmPixel == 0x40)
pixel = backgroundColor1;
else if (ecmPixel == 0x80)
pixel = backgroundColor2;
else
pixel = backgroundColor3;
}
break;
default:
pixelData = 0;
pixel = 0;
break;
} }
bitmapColumn = 0;
}
#else switch (videoMode)
{
if (!extraColorMode && !bitmapMode & !multicolorMode) case VicVideoMode.Mode000:
{
// 000
pixelData = (sr & 0x80); pixelData = (sr & 0x80);
sr <<= 1; sr <<= 1;
pixel = (pixelData != 0) ? displayC >> 8 : backgroundColor0; pixel = (pixelData != 0) ? displayC >> 8 : backgroundColor0;
} break;
else if (!extraColorMode && !bitmapMode & multicolorMode) case VicVideoMode.Mode001:
{
// 001
if ((displayC & 0x800) != 0) if ((displayC & 0x800) != 0)
{ {
// multicolor 001 // multicolor 001
@ -272,33 +188,27 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
sr <<= 1; sr <<= 1;
pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0; pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0;
} }
} break;
else if (!extraColorMode && bitmapMode & !multicolorMode) case VicVideoMode.Mode010:
{
// 010
pixelData = (sr & 0x80); pixelData = (sr & 0x80);
sr <<= 1; sr <<= 1;
pixel = (pixelData != 0) ? ((displayC >> 4) & 0xF) : (displayC & 0xF); pixel = (pixelData != 0) ? ((displayC >> 4) & 0xF) : (displayC & 0xF);
} break;
else if (!extraColorMode && bitmapMode & multicolorMode) case VicVideoMode.Mode011:
{
// 011
pixelData = (sr & 0xC0); pixelData = (sr & 0xC0);
if ((bitmapColumn & 1) != 0) if ((bitmapColumn & 1) != 0)
sr <<= 2; sr <<= 2;
if (pixelData == 0x00) if (pixelData == 0x00)
pixel = backgroundColor0; pixel = backgroundColor0;
else if (pixelData == 0x40) else if (pixelData == 0x40)
pixel = (displayC >> 4) & 0xF; pixel = (displayC >> 4) & 0xF;
else if (pixelData == 0x80) else if (pixelData == 0x80)
pixel = displayC & 0xF; pixel = displayC & 0xF;
else else
pixel = (displayC >> 8) & 0xF; pixel = (displayC >> 8) & 0xF;
} break;
else if (extraColorMode && !bitmapMode & !multicolorMode) case VicVideoMode.Mode100:
{
// 100
pixelData = (sr & 0x80); pixelData = (sr & 0x80);
sr <<= 1; sr <<= 1;
if (pixelData != 0) if (pixelData != 0)
@ -317,44 +227,28 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
else else
pixel = backgroundColor3; pixel = backgroundColor3;
} }
} break;
else if (extraColorMode && !bitmapMode & multicolorMode) default:
{
// 101
pixelData = 0; pixelData = 0;
pixel = 0; pixel = 0;
} break;
else if (extraColorMode && bitmapMode & !multicolorMode)
{
// 110
pixelData = 0;
pixel = 0;
}
else
{
// 111
pixelData = 0;
pixel = 0;
}
#endif
// 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++;
} }
// 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++;
} }
} }
} }

View File

@ -5,7 +5,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic sealed public partial class Vic
{ {
protected class Sprite protected class Sprite
{ {

View File

@ -6,7 +6,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic sealed public partial class Vic
{ {
protected int backgroundColor0; protected int backgroundColor0;
protected int backgroundColor1; protected int backgroundColor1;

View File

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
sealed public partial class Vic
{
static public int[] TimingBuilder_BA(int[] fetch)
{
int baRestart = 7;
int bacounter = 0;
int start = 0;
int length = fetch.Length;
int[] result = new int[length];
int[] spriteBA = new int[8];
int charBA = 0;
while (true)
{
if (fetch[start] == 0)
break;
start++;
}
while (true)
{
if (fetch[start] == 0x200)
break;
start--;
}
if (start < 0)
start += length;
int offset = start;
while (true)
{
int ba = 0x0888;
if (fetch[offset] == 0x200)
charBA = baRestart;
else if ((fetch[offset] & 0xFF00) == 0x0000)
spriteBA[fetch[offset] & 0x007] = baRestart;
for (int i = 0; i < 8; i++)
{
if (spriteBA[i] > 0)
{
ba <<= 4;
ba |= i;
spriteBA[i]--;
}
}
ba &= 0x0FFF;
if (charBA > 0)
{
ba = 0x1000;
charBA--;
}
result[offset] = ba;
offset--;
if (offset < 0)
offset += length;
if (offset == start)
break;
}
for (int i = 0; i < length; i += 2)
{
result[i] = result[i + 1];
}
return result;
}
static public int[] TimingBuilder_Fetch(int[] timing, int sprite)
{
int length = timing.Length;
int[] result = new int[length];
int offset;
int index = -1;
int refreshCounter = 0;
bool spriteActive = false;
int spriteIndex = 0;
int spritePhase = 0;
int charCounter = 0;
for (int i = 0; i < length; i++)
{
result[i++] = 0x500;
result[i] = 0x100;
}
while (true)
{
index++;
if (index >= length)
index -= length;
offset = timing[index];
if (charCounter > 0)
{
result[index] = (charCounter & 1) == 0 ? 0x200 : 0x300;
charCounter--;
if (charCounter == 0)
break;
}
if (refreshCounter > 0)
{
result[index] = (refreshCounter & 1) == 0 ? 0x500 : 0x100;
refreshCounter--;
if (refreshCounter == 0)
charCounter = 80;
}
if (offset == sprite)
{
spriteActive = true;
}
if (spriteActive)
{
result[index] = (spriteIndex | (spritePhase << 4));
spritePhase++;
if (spritePhase == 4)
{
spritePhase = 0;
spriteIndex++;
if (spriteIndex == 8)
{
spriteActive = false;
refreshCounter = 9;
}
}
}
}
return result.ToArray();
}
static public int[] TimingBuilder_XRaster(int start, int width, int count, int delayOffset, int delayAmount)
{
List<int> result = new List<int>();
int rasterX = start;
bool delayed = false;
count >>= 2;
for (int i = 0; i < count; i++)
{
result.Add(rasterX);
if (!delayed)
{
rasterX += 4;
if (rasterX >= width)
rasterX -= width;
}
else
{
delayAmount--;
if (delayAmount <= 0)
delayed = false;
continue;
}
if (rasterX == delayOffset && delayAmount > 0)
delayed = true;
}
return result.ToArray();
}
}
}

View File

@ -2,7 +2,7 @@
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic : IVideoProvider sealed public partial class Vic : IVideoProvider
{ {
protected int[] buf; protected int[] buf;
protected int bufHeight; protected int bufHeight;

View File

@ -3,7 +3,7 @@ using System.Drawing;
namespace BizHawk.Emulation.Computers.Commodore64.MOS namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
public abstract partial class Vic sealed public partial class Vic
{ {
public Func<int, byte> ReadColorRam; public Func<int, byte> ReadColorRam;
public Func<int, byte> ReadMemory; public Func<int, byte> ReadMemory;