Commodore64: Completed initial experimental Vic, pending testing.
This commit is contained in:
parent
cfc2b141bf
commit
99a5c3e109
|
@ -7,12 +7,18 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
{
|
{
|
||||||
sealed public partial class Vic
|
sealed public partial class Vic
|
||||||
{
|
{
|
||||||
|
const int AEC_DELAY = 7;
|
||||||
|
const int GRAPHICS_GENERATOR_DELAY = 12;
|
||||||
|
const int BORDER_GENERATOR_DELAY = 8;
|
||||||
|
const int BORDER_GENERATOR_DELAY_BIT = 1 << BORDER_GENERATOR_DELAY;
|
||||||
|
|
||||||
int address;
|
int address;
|
||||||
bool aec;
|
bool aec;
|
||||||
int aecCounter;
|
int aecCounter;
|
||||||
bool ba;
|
bool ba;
|
||||||
bool badLineCondition;
|
bool badLineCondition;
|
||||||
bool badLineEnable;
|
bool badLineEnable;
|
||||||
|
int borderDelay;
|
||||||
int characterData;
|
int characterData;
|
||||||
int[] characterMatrix;
|
int[] characterMatrix;
|
||||||
int colorData;
|
int colorData;
|
||||||
|
@ -22,8 +28,10 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
int graphicsGeneratorCharacter;
|
int graphicsGeneratorCharacter;
|
||||||
int graphicsGeneratorColor;
|
int graphicsGeneratorColor;
|
||||||
int graphicsGeneratorData;
|
int graphicsGeneratorData;
|
||||||
|
bool graphicsGeneratorMulticolor;
|
||||||
int graphicsGeneratorPixel;
|
int graphicsGeneratorPixel;
|
||||||
int graphicsGeneratorPixelData;
|
int graphicsGeneratorPixelData;
|
||||||
|
bool graphicsGeneratorShiftToggle;
|
||||||
bool idleState;
|
bool idleState;
|
||||||
bool mainBorder;
|
bool mainBorder;
|
||||||
int mainBorderEnd;
|
int mainBorderEnd;
|
||||||
|
@ -35,6 +43,12 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
int rasterX;
|
int rasterX;
|
||||||
int refreshCounter;
|
int refreshCounter;
|
||||||
int rowCounter;
|
int rowCounter;
|
||||||
|
Sprite spriteBuffer;
|
||||||
|
int spriteGeneratorBackgroundData;
|
||||||
|
int spriteGeneratorPixel;
|
||||||
|
int spriteGeneratorPixelData;
|
||||||
|
bool spriteGeneratorPixelEnabled;
|
||||||
|
bool spriteGeneratorPriority;
|
||||||
bool verticalBorder;
|
bool verticalBorder;
|
||||||
int verticalBorderEnd;
|
int verticalBorderEnd;
|
||||||
int verticalBorderStart;
|
int verticalBorderStart;
|
||||||
|
@ -59,7 +73,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
videoBuffer = new int[screenWidth * screenHeight];
|
videoBuffer = new int[screenWidth * screenHeight];
|
||||||
|
|
||||||
// reset registers
|
// reset registers
|
||||||
pixelBufferLength = 12;
|
pixelBufferLength = GRAPHICS_GENERATOR_DELAY;
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +85,81 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
verticalBorderStart = rowSelect ? 0x33 : 0x37;
|
verticalBorderStart = rowSelect ? 0x33 : 0x37;
|
||||||
verticalBorderEnd = rowSelect ? 0xFB : 0xF7;
|
verticalBorderEnd = rowSelect ? 0xFB : 0xF7;
|
||||||
|
|
||||||
|
// process badline enable & condition
|
||||||
|
if (rasterY >= 0x30 && rasterY < 0xF8)
|
||||||
|
{
|
||||||
|
if (rasterY == 0x30 && displayEnable)
|
||||||
|
badLineEnable = true;
|
||||||
|
if (badLineEnable && ((rasterY & 0x7) == yScroll))
|
||||||
|
badLineCondition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process sprites on phi1
|
||||||
|
foreach (Sprite sprite in sprites)
|
||||||
|
{
|
||||||
|
// process expansion flipflop
|
||||||
|
if (!sprite.ExpandY)
|
||||||
|
sprite.ExpandYToggle = true;
|
||||||
|
else if (rasterX == spriteDMACheckStart)
|
||||||
|
sprite.ExpandYToggle = !sprite.ExpandYToggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process sprite dma enable
|
||||||
|
if (rasterX == spriteDMACheckStart || rasterX == spriteDMACheckEnd)
|
||||||
|
{
|
||||||
|
foreach (Sprite sprite in sprites)
|
||||||
|
{
|
||||||
|
if (sprite.Enabled && !sprite.DMA & sprite.Y == (rasterY & 0xFF))
|
||||||
|
{
|
||||||
|
sprite.DMA = true;
|
||||||
|
sprite.CounterBase = 0;
|
||||||
|
if (sprite.ExpandY)
|
||||||
|
sprite.ExpandYToggle = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: VERIFY THIS IS THE CORRECT TIMING
|
||||||
|
// (the VIC doc I used doesn't specify exactly when this happens)
|
||||||
|
sprite.DataShiftEnable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process sprite display
|
||||||
|
if (rasterX == spriteCounterCheckStart)
|
||||||
|
{
|
||||||
|
foreach (Sprite sprite in sprites)
|
||||||
|
{
|
||||||
|
sprite.Counter = sprite.CounterBase;
|
||||||
|
if (sprite.DMA && sprite.Y == (rasterY & 0xFF))
|
||||||
|
sprite.Display = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process sprite counter base
|
||||||
|
if (rasterX == spriteDMADisableStart)
|
||||||
|
{
|
||||||
|
foreach (Sprite sprite in sprites)
|
||||||
|
{
|
||||||
|
if (sprite.ExpandYToggle)
|
||||||
|
sprite.CounterBase += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process sprite dma disable
|
||||||
|
if (rasterX == spriteDMADisableEnd)
|
||||||
|
{
|
||||||
|
foreach (Sprite sprite in sprites)
|
||||||
|
{
|
||||||
|
if (sprite.ExpandYToggle)
|
||||||
|
sprite.CounterBase += 1;
|
||||||
|
if (sprite.CounterBase == 63)
|
||||||
|
{
|
||||||
|
sprite.DMA = false;
|
||||||
|
sprite.Display = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// process hblank trigger
|
// process hblank trigger
|
||||||
|
@ -133,6 +222,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
rasterY = 0;
|
rasterY = 0;
|
||||||
videoCounterBase = 0;
|
videoCounterBase = 0;
|
||||||
videoBufferIndex = 0;
|
videoBufferIndex = 0;
|
||||||
|
badLineEnable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,13 +259,16 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
}
|
}
|
||||||
if (sprite.Fetch)
|
if (sprite.Fetch)
|
||||||
{
|
{
|
||||||
fetchState = FetchState.Sprite;
|
if (sprite.DMA)
|
||||||
ba = false;
|
{
|
||||||
|
fetchState = FetchState.Sprite;
|
||||||
|
ba = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (rasterX == sprite.FetchStart)
|
else if (rasterX == sprite.FetchStart)
|
||||||
{
|
{
|
||||||
sprite.Fetch = sprite.Enabled;
|
sprite.Fetch = true;
|
||||||
fetchState = FetchState.Pointer;
|
fetchState = FetchState.Pointer;
|
||||||
ba = !sprite.Fetch;
|
ba = !sprite.Fetch;
|
||||||
break;
|
break;
|
||||||
|
@ -187,7 +280,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
// determine AEC state
|
// determine AEC state
|
||||||
if (ba)
|
if (ba)
|
||||||
{
|
{
|
||||||
aecCounter = 7;
|
aecCounter = AEC_DELAY;
|
||||||
aec = true;
|
aec = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -241,6 +334,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
case FetchState.Pointer:
|
case FetchState.Pointer:
|
||||||
address = spriteIndex | videoMemory | 0x03F8;
|
address = spriteIndex | videoMemory | 0x03F8;
|
||||||
data = ReadRam(address);
|
data = ReadRam(address);
|
||||||
|
sprites[spriteIndex].Pointer = address;
|
||||||
break;
|
break;
|
||||||
case FetchState.Refresh:
|
case FetchState.Refresh:
|
||||||
address = refreshCounter | 0x3F00;
|
address = refreshCounter | 0x3F00;
|
||||||
|
@ -249,44 +343,38 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
refreshCounter &= 0xFF;
|
refreshCounter &= 0xFF;
|
||||||
break;
|
break;
|
||||||
case FetchState.Sprite:
|
case FetchState.Sprite:
|
||||||
address = data | sprites[spriteIndex].Counter;
|
spriteBuffer = sprites[spriteIndex];
|
||||||
|
address = (spriteBuffer.Pointer << 6) | spriteBuffer.Counter;
|
||||||
data = ReadRam(address);
|
data = ReadRam(address);
|
||||||
|
spriteBuffer.Counter++;
|
||||||
|
spriteBuffer.Counter &= 0x3F;
|
||||||
|
spriteBuffer.Data <<= 8;
|
||||||
|
spriteBuffer.Data |= data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// render 4 pixels
|
// render 4 pixels (there are 8 per cycle)
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
// pixelbuffer -> videobuffer
|
// initialize background pixel data generator
|
||||||
if (!hBlank && !vBlank)
|
|
||||||
{
|
|
||||||
videoBuffer[videoBufferIndex] = palette[pixelBuffer[pixelBufferIndex]];
|
|
||||||
videoBufferIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// graphics generator
|
|
||||||
if ((rasterX & 0x7) == xScroll)
|
if ((rasterX & 0x7) == xScroll)
|
||||||
{
|
{
|
||||||
graphicsGeneratorCharacter = characterData;
|
graphicsGeneratorCharacter = characterData;
|
||||||
graphicsGeneratorColor = colorData;
|
graphicsGeneratorColor = colorData;
|
||||||
graphicsGeneratorData = graphicsData;
|
graphicsGeneratorData = graphicsData;
|
||||||
|
graphicsGeneratorMulticolor = !(!multiColorMode || (!bitmapMode && ((colorData & 0x4) == 0)));
|
||||||
|
graphicsGeneratorShiftToggle = !graphicsGeneratorMulticolor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// shift graphics data
|
// shift graphics data
|
||||||
if (!multiColorMode || (!bitmapMode && ((colorData & 0x4) == 0)))
|
if (graphicsGeneratorShiftToggle)
|
||||||
{
|
graphicsGeneratorPixelData >>= graphicsGeneratorMulticolor ? 2 : 1;
|
||||||
graphicsGeneratorPixelData = graphicsData & 0x01;
|
graphicsGeneratorShiftToggle = !graphicsGeneratorShiftToggle || !graphicsGeneratorMulticolor;
|
||||||
graphicsData >>= 1;
|
|
||||||
}
|
|
||||||
else if ((rasterX & 0x7) == xScroll)
|
|
||||||
{
|
|
||||||
graphicsGeneratorPixelData = graphicsData & 0x03;
|
|
||||||
graphicsData >>= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate pixel
|
// generate data and color for the pixelbuffer
|
||||||
if (!verticalBorder)
|
if (!verticalBorder)
|
||||||
{
|
{
|
||||||
|
// graphics generator
|
||||||
if (extraColorMode)
|
if (extraColorMode)
|
||||||
{
|
{
|
||||||
if (bitmapMode)
|
if (bitmapMode)
|
||||||
|
@ -379,7 +467,80 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
graphicsGeneratorPixelData = 0x0;
|
graphicsGeneratorPixelData = 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pixel generator -> pixelbuffer
|
// sprite generator
|
||||||
|
spriteGeneratorBackgroundData = pixelDataBuffer[pixelBufferIndex];
|
||||||
|
spriteIndex = 0;
|
||||||
|
spriteGeneratorPixelEnabled = false;
|
||||||
|
foreach (Sprite sprite in sprites)
|
||||||
|
{
|
||||||
|
if (sprite.Display)
|
||||||
|
{
|
||||||
|
if (sprite.X == rasterX)
|
||||||
|
{
|
||||||
|
// enable sprite shift register on X compare
|
||||||
|
sprite.DataShiftEnable = true;
|
||||||
|
sprite.ExpandXToggle = !sprite.ExpandX;
|
||||||
|
sprite.MultiColorToggle = !sprite.Multicolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sprite.DataShiftEnable)
|
||||||
|
{
|
||||||
|
// bit select based on multicolor
|
||||||
|
if (sprite.Multicolor)
|
||||||
|
sprite.OutputData = sprite.Data & 0x300000;
|
||||||
|
else
|
||||||
|
sprite.OutputData = sprite.Data & 0x200000;
|
||||||
|
|
||||||
|
// shift bits in the shift register
|
||||||
|
if (sprite.MultiColorToggle && sprite.ExpandXToggle)
|
||||||
|
sprite.Data <<= sprite.Multicolor ? 2 : 1;
|
||||||
|
|
||||||
|
// flipflops used to determine when to shift bits
|
||||||
|
sprite.MultiColorToggle = !sprite.MultiColorToggle || !sprite.Multicolor;
|
||||||
|
if (sprite.MultiColorToggle)
|
||||||
|
sprite.ExpandXToggle = !sprite.ExpandXToggle || !sprite.ExpandX;
|
||||||
|
|
||||||
|
// determine sprite collision and color
|
||||||
|
if (sprite.OutputData != 0x000000)
|
||||||
|
{
|
||||||
|
if (!spriteGeneratorPixelEnabled)
|
||||||
|
{
|
||||||
|
spriteGeneratorPixelEnabled = true;
|
||||||
|
spriteGeneratorPixelData = spriteIndex;
|
||||||
|
spriteGeneratorPriority = sprite.Priority;
|
||||||
|
|
||||||
|
// determine sprite pixel output for topmost sprite only
|
||||||
|
if (sprite.OutputData == 0x100000)
|
||||||
|
sprite.OutputPixel = spriteMultiColor[0];
|
||||||
|
else if (sprite.OutputData == 0x200000)
|
||||||
|
sprite.OutputPixel = sprite.Color;
|
||||||
|
else if (sprite.OutputData == 0x300000)
|
||||||
|
sprite.OutputPixel = spriteMultiColor[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprites[spriteGeneratorPixelData].SpriteCollision = true;
|
||||||
|
sprite.SpriteCollision = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine sprite-background collision
|
||||||
|
if ((spriteGeneratorBackgroundData & 0x2) != 0)
|
||||||
|
sprite.DataCollision = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spriteIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// combine the pixels
|
||||||
|
if (spriteGeneratorPixelEnabled && (!spriteGeneratorPriority || ((spriteGeneratorBackgroundData & 0x2) == 0)))
|
||||||
|
pixel = spriteGeneratorPixel;
|
||||||
|
else
|
||||||
|
pixel = pixelBuffer[pixelBufferIndex];
|
||||||
|
|
||||||
|
// pixel generator data -> pixeldatabuffer
|
||||||
|
pixelDataBuffer[pixelBufferIndex] = graphicsGeneratorPixelData;
|
||||||
pixelBuffer[pixelBufferIndex] = graphicsGeneratorPixel;
|
pixelBuffer[pixelBufferIndex] = graphicsGeneratorPixel;
|
||||||
|
|
||||||
// border unit comparisons
|
// border unit comparisons
|
||||||
|
@ -395,17 +556,24 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
mainBorder = false;
|
mainBorder = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// border unit -> pixelbuffer
|
// border unit (delay of 8 pixels, we use a shift register)
|
||||||
|
borderDelay <<= 1;
|
||||||
if (mainBorder || verticalBorder)
|
if (mainBorder || verticalBorder)
|
||||||
pixelBuffer[borderPixelBufferIndex] = borderColor;
|
borderDelay |= 1;
|
||||||
|
if ((borderDelay & BORDER_GENERATOR_DELAY_BIT) != 0)
|
||||||
|
pixel = borderColor;
|
||||||
|
|
||||||
|
// rendered pixel -> videobuffer
|
||||||
|
if (!hBlank && !vBlank)
|
||||||
|
{
|
||||||
|
videoBuffer[videoBufferIndex] = palette[pixel];
|
||||||
|
videoBufferIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
// advance pixelbuffer
|
// advance pixelbuffer
|
||||||
pixelBufferIndex++;
|
pixelBufferIndex++;
|
||||||
if (pixelBufferIndex == pixelBufferLength)
|
if (pixelBufferIndex == pixelBufferLength)
|
||||||
pixelBufferIndex = 0;
|
pixelBufferIndex = 0;
|
||||||
borderPixelBufferIndex++;
|
|
||||||
if (borderPixelBufferIndex == pixelBufferLength)
|
|
||||||
borderPixelBufferIndex = 0;
|
|
||||||
|
|
||||||
// horizontal raster delay found in 6567R8
|
// horizontal raster delay found in 6567R8
|
||||||
if (rasterDelay > 0)
|
if (rasterDelay > 0)
|
||||||
|
@ -444,7 +612,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
pixelBuffer = new int[pixelBufferLength];
|
pixelBuffer = new int[pixelBufferLength];
|
||||||
pixelDataBuffer = new int[pixelBufferLength];
|
pixelDataBuffer = new int[pixelBufferLength];
|
||||||
pixelBufferIndex = 0;
|
pixelBufferIndex = 0;
|
||||||
borderPixelBufferIndex = 8;
|
|
||||||
|
|
||||||
// internal screen row buffer
|
// internal screen row buffer
|
||||||
colorMatrix = new int[40];
|
colorMatrix = new int[40];
|
||||||
|
|
|
@ -14,9 +14,18 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
public int BAStart; //precalculated
|
public int BAStart; //precalculated
|
||||||
public int Counter; //MC
|
public int Counter; //MC
|
||||||
public int CounterBase; //MCBASE
|
public int CounterBase; //MCBASE
|
||||||
public int Data; //24-bit shift register
|
public Int32 Data; //24-bit shift register
|
||||||
|
public bool DataShiftEnable;
|
||||||
|
public bool Display;
|
||||||
|
public bool DMA;
|
||||||
|
public bool ExpandXToggle;
|
||||||
|
public bool ExpandYToggle;
|
||||||
public bool Fetch;
|
public bool Fetch;
|
||||||
public int FetchStart; //precalculated
|
public int FetchStart; //precalculated
|
||||||
|
public bool MultiColorToggle;
|
||||||
|
public int OutputData;
|
||||||
|
public int OutputPixel;
|
||||||
|
public int Pointer;
|
||||||
|
|
||||||
public int Color;
|
public int Color;
|
||||||
public bool DataCollision;
|
public bool DataCollision;
|
||||||
|
|
|
@ -37,6 +37,12 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
int screenXStart;
|
int screenXStart;
|
||||||
int screenYEnd;
|
int screenYEnd;
|
||||||
int screenYStart;
|
int screenYStart;
|
||||||
|
int spriteCounterCheckStart;
|
||||||
|
int spriteDMACheckEnd;
|
||||||
|
int spriteDMACheckStart;
|
||||||
|
int spriteDMADisableEnd;
|
||||||
|
int spriteDMADisableStart;
|
||||||
|
int spriteShiftDisableStart;
|
||||||
bool vBlank;
|
bool vBlank;
|
||||||
|
|
||||||
void InitTiming(VicTiming timing)
|
void InitTiming(VicTiming timing)
|
||||||
|
@ -60,6 +66,12 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
rasterWidth = timing.HSize;
|
rasterWidth = timing.HSize;
|
||||||
rasterAdvance = timing.LineStart;
|
rasterAdvance = timing.LineStart;
|
||||||
rasterCount = timing.VSize;
|
rasterCount = timing.VSize;
|
||||||
|
spriteDMACheckStart = characterBAEnd;
|
||||||
|
spriteDMACheckEnd = (spriteDMACheckStart + 8) % timing.HSize;
|
||||||
|
spriteCounterCheckStart = (spriteDMACheckEnd + 16) % timing.HSize;
|
||||||
|
spriteShiftDisableStart = timing.HBlankStart;
|
||||||
|
spriteDMADisableStart = characterFetchStart;
|
||||||
|
spriteDMADisableEnd = (characterFetchStart + 8) % timing.HSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
||||||
{
|
{
|
||||||
sealed public partial class Vic : IVideoProvider
|
sealed public partial class Vic : IVideoProvider
|
||||||
{
|
{
|
||||||
int borderPixelBufferIndex;
|
|
||||||
int[] pixelBuffer;
|
int[] pixelBuffer;
|
||||||
int pixelBufferIndex;
|
int pixelBufferIndex;
|
||||||
int pixelBufferLength;
|
int pixelBufferLength;
|
||||||
|
|
Loading…
Reference in New Issue