Commodore64: Experimental Vic implementation nearly complete.

This commit is contained in:
saxxonpike 2013-08-21 12:12:30 +00:00
parent c827d42f2d
commit cfc2b141bf
1 changed files with 255 additions and 18 deletions

View File

@ -14,17 +14,30 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
bool badLineCondition;
bool badLineEnable;
int characterData;
int[] characterMatrix;
int colorData;
int[] colorMatrix;
int data;
int graphicsData;
int graphicsGeneratorCharacter;
int graphicsGeneratorColor;
int graphicsGeneratorData;
int graphicsGeneratorPixel;
int graphicsGeneratorPixelData;
bool idleState;
bool mainBorder;
int mainBorderEnd;
int mainBorderStart;
bool phi0;
int phi1Data;
int pixel;
int[] pixelDataBuffer;
int rasterX;
int refreshCounter;
int rowCounter;
bool verticalBorder;
int verticalBorderEnd;
int verticalBorderStart;
int videoCounter;
int videoCounterBase;
int videoMatrixLineIndex;
@ -42,6 +55,9 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
if (screenYEnd < screenYStart)
screenHeight += rasterCount;
// create video buffer
videoBuffer = new int[screenWidth * screenHeight];
// reset registers
pixelBufferLength = 12;
Reset();
@ -49,16 +65,39 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
public void Clock()
{
// these should be cached somewhere
mainBorderStart = columnSelect ? 0x18 : 0x1F;
mainBorderEnd = columnSelect ? 0x158 : 0x14F;
verticalBorderStart = rowSelect ? 0x33 : 0x37;
verticalBorderEnd = rowSelect ? 0xFB : 0xF7;
do
{
// process horizontal triggers
// process hblank trigger
if (rasterX == screenXStart)
hBlank = false;
else if (rasterX == screenXEnd)
else if (rasterX == screenXEnd && !hBlank)
{
hBlank = true;
rasterDelay = hBlankDelay;
// process row counter
if (rowCounter == 7)
{
idleState = true;
videoCounterBase = videoCounter;
}
else if (!idleState)
rowCounter++;
// process vertical border flipflop
if (rasterY == mainBorderEnd)
verticalBorder = true;
if (rasterY == mainBorderStart && displayEnable)
verticalBorder = false;
}
// process character BA trigger
if (rasterX == characterBAStart)
characterBA = false;
else if (rasterX == characterBAEnd)
@ -66,13 +105,21 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
characterBA = true;
graphicsFetch = false;
}
// process character fetch trigger
if (rasterX == characterFetchStart)
{
graphicsFetch = true;
refreshFetch = false;
}
// process new line/raster triggers
if (rasterX == rasterWidth)
{
rasterX = 0;
videoCounter = videoCounterBase;
videoMatrixLineIndex = 0;
}
else if (rasterX == rasterAdvance)
{
// process vertical triggers
@ -81,20 +128,26 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
vBlank = false;
else if (rasterY == screenYEnd)
vBlank = true;
else if (rasterY == rasterCount)
{
rasterY = 0;
videoCounterBase = 0;
videoBufferIndex = 0;
}
}
// determine BA and fetch state
ba = true;
// None is used for when we don't assert control.
fetchState = phi0 ? FetchState.Idle : FetchState.None;
// determine BA state
ba = true;
if (characterBA)
{
// covers badlines and display area fetches
characterFetch = (badLineCondition && badLineEnable);
ba = !characterFetch;
fetchState = phi0 ? FetchState.Graphics : (characterFetch ? FetchState.Character : FetchState.None);
fetchState = phi0 ? FetchState.Graphics : FetchState.Character;
}
else if (refreshFetch)
{
@ -104,6 +157,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
else
{
// covers sprite pointer and data fetches
spriteIndex = 0;
foreach (Sprite sprite in sprites)
{
if (rasterX == sprite.BAStart)
@ -113,18 +167,20 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
sprite.BA = true;
sprite.Fetch = false;
}
if (!sprite.BA && sprite.Enabled)
if (sprite.Fetch)
{
fetchState = FetchState.Sprite;
ba = false;
break;
}
if (rasterX == sprite.FetchStart)
else if (rasterX == sprite.FetchStart)
{
sprite.Fetch = true;
sprite.Fetch = sprite.Enabled;
fetchState = FetchState.Pointer;
ba = !sprite.Fetch;
break;
}
spriteIndex++;
}
}
@ -147,17 +203,34 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
switch (fetchState)
{
case FetchState.Character:
address = videoCounter | videoMemory;
colorData = ReadColorRam(address);
characterData = ReadRam(address);
data = characterData;
if (badLineCondition)
{
address = videoCounter | videoMemory;
colorMatrix[videoMatrixLineIndex] = colorData = ReadColorRam(address);
characterMatrix[videoMatrixLineIndex] = characterData = data = ReadRam(address);
}
else if (!idleState)
{
colorData = colorMatrix[videoMatrixLineIndex];
characterData = characterMatrix[videoMatrixLineIndex];
}
else
{
colorData = 0;
characterData = 0;
}
break;
case FetchState.Graphics:
address = (extraColorMode ? 0x39FF : 0x3FFF);
if (bitmapMode)
address &= (rowCounter | (videoCounter << 3) | (characterBitmap & 0x2000));
else
address &= (rowCounter | (data << 3) | characterBitmap);
if (!idleState)
{
if (bitmapMode)
address &= (rowCounter | (videoCounter << 3) | (characterBitmap & 0x2000));
else
address &= (rowCounter | (characterData << 3) | characterBitmap);
videoMatrixLineIndex++;
videoMatrixLineIndex &= 0x3F;
}
data = ReadRam(address);
graphicsData = data;
break;
@ -172,6 +245,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
case FetchState.Refresh:
address = refreshCounter | 0x3F00;
data = ReadRam(address);
refreshCounter--;
refreshCounter &= 0xFF;
break;
case FetchState.Sprite:
address = data | sprites[spriteIndex].Counter;
@ -182,20 +257,169 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
// render 4 pixels
for (int i = 0; i < 4; i++)
{
// pixelbuffer -> videobuffer
if (!hBlank && !vBlank)
{
videoBuffer[videoBufferIndex] = palette[pixelBuffer[pixelBufferIndex]];
videoBufferIndex++;
}
// graphics generator
if ((rasterX & 0x7) == xScroll)
{
graphicsGeneratorCharacter = characterData;
graphicsGeneratorColor = colorData;
graphicsGeneratorData = graphicsData;
}
// shift graphics data
if (!multiColorMode || (!bitmapMode && ((colorData & 0x4) == 0)))
{
graphicsGeneratorPixelData = graphicsData & 0x01;
graphicsData >>= 1;
}
else if ((rasterX & 0x7) == xScroll)
{
graphicsGeneratorPixelData = graphicsData & 0x03;
graphicsData >>= 2;
}
// generate pixel
if (!verticalBorder)
{
if (extraColorMode)
{
if (bitmapMode)
{
// ECM=1, BMM=1, MCM=1
// ECM=1, BMM=1, MCM=0
graphicsGeneratorPixel = 0;
}
else
{
if (multiColorMode)
{
// ECM=1, BMM=0, MCM=1
graphicsGeneratorPixel = 0;
}
else
{
// ECM=1, BMM=0, MCM=0
if (graphicsGeneratorPixelData == 0)
graphicsGeneratorPixel = backgroundColor[characterData >> 6];
else
graphicsGeneratorPixel = colorData;
}
}
}
else
{
if (bitmapMode)
{
if (multiColorMode)
{
// ECM=0, BMM=1, MCM=1
if (graphicsGeneratorPixelData == 0x0)
graphicsGeneratorPixel = backgroundColor[0];
else if (graphicsGeneratorPixelData == 0x1)
graphicsGeneratorPixel = characterData >> 4;
else if (graphicsGeneratorPixelData == 0x2)
graphicsGeneratorPixel = (characterData & 0xF);
else
graphicsGeneratorPixel = colorData;
}
else
{
// ECM=0, BMM=1, MCM=0
if (graphicsGeneratorPixelData == 0x0)
graphicsGeneratorPixel = (characterData & 0xF);
else
graphicsGeneratorPixel = characterData >> 4;
}
}
else
{
if (multiColorMode)
{
// ECM=0, BMM=0, MCM=1
if ((colorData & 0x4) == 0)
{
if (graphicsGeneratorPixelData == 0x0)
graphicsGeneratorPixel = backgroundColor[0];
else
graphicsGeneratorPixel = (colorData & 0x7);
}
else
{
if (graphicsGeneratorPixelData == 0x0)
graphicsGeneratorPixel = backgroundColor[0];
else if (graphicsGeneratorPixelData == 0x1)
graphicsGeneratorPixel = backgroundColor[1];
else if (graphicsGeneratorPixelData == 0x2)
graphicsGeneratorPixel = backgroundColor[2];
else
graphicsGeneratorPixel = (colorData & 0x7);
}
}
else
{
// ECM=0, BMM=0, MCM=0
if (graphicsGeneratorPixelData == 0x0)
graphicsGeneratorPixel = backgroundColor[0];
else
graphicsGeneratorPixel = colorData;
}
}
}
}
else
{
// vertical border enabled, disable output
graphicsGeneratorPixel = backgroundColor[0];
graphicsGeneratorPixelData = 0x0;
}
// pixel generator -> pixelbuffer
pixelBuffer[pixelBufferIndex] = graphicsGeneratorPixel;
// border unit comparisons
if (rasterX == verticalBorderStart)
mainBorder = true;
else if (rasterX == verticalBorderEnd)
{
if (rasterY == mainBorderStart)
verticalBorder = true;
if (rasterY == mainBorderEnd && displayEnable)
verticalBorder = false;
if (!verticalBorder)
mainBorder = false;
}
// border unit -> pixelbuffer
if (mainBorder || verticalBorder)
pixelBuffer[borderPixelBufferIndex] = borderColor;
// advance pixelbuffer
pixelBufferIndex++;
if (pixelBufferIndex == pixelBufferLength)
pixelBufferIndex = 0;
borderPixelBufferIndex++;
if (borderPixelBufferIndex == pixelBufferLength)
borderPixelBufferIndex = 0;
// horizontal raster delay found in 6567R8
if (rasterDelay > 0)
rasterDelay--;
else
rasterX++;
}
if (!phi0)
phi1Data = data;
phi0 = !phi0;
} while (phi0);
// at the end, clock other devices if applicable
ClockPhi0();
}
@ -218,8 +442,21 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
// empty out the pixel buffer
pixelBuffer = new int[pixelBufferLength];
pixelDataBuffer = new int[pixelBufferLength];
pixelBufferIndex = 0;
borderPixelBufferIndex = 8;
// internal screen row buffer
colorMatrix = new int[40];
characterMatrix = new int[40];
rowCounter = 0;
videoCounter = 0;
videoCounterBase = 0;
videoMatrixLineIndex = 0;
// border unit
mainBorder = true;
verticalBorder = true;
}
}
}