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.Sprite.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\Sync.cs" />
<Compile Include="Computers\Commodore64\Tape\VIC1530.cs" />

View File

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

View File

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

View File

@ -1,244 +1,17 @@
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// 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);
static int[] ba = Vic.TimingBuilder_BA(fetch);
static int[][] pipeline = new int[][]
{
new int[] // xposition
{
0x0194, 0x0198,
0x019C, 0x01A0,
0x01A4, 0x01A8,
0x01AC, 0x01B0,
0x01B4, 0x01B8,
0x01BC, 0x01C0,
0x01C4, 0x01C8,
0x01CC, 0x01D0,
0x01D4, 0x01D8,
0x01DC, 0x01E0,
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
},
timing,
fetch,
ba,
new int[] // actions
{
0, 0,
@ -256,12 +29,12 @@
0, 0,
0, 0,
0, 0,
0, pipelineUpdateVc,
0, pipelineChkSprChunch,
0, Vic.pipelineUpdateVc,
0, Vic.pipelineChkSprChunch,
0, pipelineUpdateMcBase,
0, pipelineChkBrdL1,
0, pipelineChkBrdL0,
0, Vic.pipelineUpdateMcBase,
0, Vic.pipelineChkBrdL1,
0, Vic.pipelineChkBrdL0,
0, 0,
0, 0,
@ -305,11 +78,11 @@
0, 0,
0, 0,
0, 0,
pipelineChkSprDma, 0,
Vic.pipelineChkSprDma, 0,
pipelineChkSprDma, pipelineChkBrdR0 | pipelineChkSprExp,
0, pipelineChkBrdR1,
pipelineChkSprDisp, pipelineUpdateRc,
Vic.pipelineChkSprDma, Vic.pipelineChkBrdR0 | Vic.pipelineChkSprExp,
0, Vic.pipelineChkBrdR1,
Vic.pipelineChkSprDisp, Vic.pipelineUpdateRc,
0, 0,
0, 0,
@ -319,9 +92,9 @@
}
};
public MOS6569()
: base(63, 312, pipeline, 17734472 / 18)
static public Vic Create()
{
return new Vic(63, 312, pipeline, 17734472 / 18);
}
}
}

View File

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

View File

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

View File

@ -5,7 +5,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Vic
sealed public partial class Vic
{
protected int ecmPixel;
protected int pixel;
@ -32,8 +32,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
}
private void Render()
{
{
renderEnabled = bufRect.Contains(bufPoint);
@ -117,7 +115,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
// sprite-sprite collision
if (pixelOwner >= 8)
{
if (!spr.priority || (pixelDataBuffer[pixelBackgroundBufferIndex] < 0x2))
if (!spr.priority || (pixelDataBuffer[pixelBackgroundBufferIndex] < 0x80))
pixel = sprPixel;
pixelOwner = j;
}
@ -159,7 +157,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
bitmapColumn = 0;
}
#if true
switch (videoMode)
{
case VicVideoMode.Mode000:
@ -237,108 +234,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
break;
}
#else
if (!extraColorMode && !bitmapMode & !multicolorMode)
{
// 000
pixelData = (sr & 0x80);
sr <<= 1;
pixel = (pixelData != 0) ? displayC >> 8 : backgroundColor0;
}
else if (!extraColorMode && !bitmapMode & multicolorMode)
{
// 001
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;
}
}
else if (!extraColorMode && bitmapMode & !multicolorMode)
{
// 010
pixelData = (sr & 0x80);
sr <<= 1;
pixel = (pixelData != 0) ? ((displayC >> 4) & 0xF) : (displayC & 0xF);
}
else if (!extraColorMode && bitmapMode & multicolorMode)
{
// 011
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;
}
else if (extraColorMode && !bitmapMode & !multicolorMode)
{
// 100
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;
}
}
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;
}
#endif
// put the rendered pixel into the background buffer
pixelDataBuffer[pixelBackgroundBufferIndex] = pixelData;
pixelBackgroundBuffer[pixelBackgroundBufferIndex] = pixel;
@ -357,5 +252,4 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
}
}
}
}
}

View File

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

View File

@ -6,7 +6,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Vic
sealed public partial class Vic
{
protected int backgroundColor0;
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
{
public abstract partial class Vic : IVideoProvider
sealed public partial class Vic : IVideoProvider
{
protected int[] buf;
protected int bufHeight;

View File

@ -3,7 +3,7 @@ using System.Drawing;
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> ReadMemory;