Commodore64: Experimental VIC updated.

This commit is contained in:
saxxonpike 2013-08-21 09:38:22 +00:00
parent 6b454f3a78
commit c827d42f2d
8 changed files with 358 additions and 90 deletions

View File

@ -113,6 +113,7 @@
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Userport.cs" />
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Vic.Registers.cs" />
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Vic.Settings.cs" />
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Vic.Sprite.cs" />
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Vic.State.cs" />
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Vic.Timing.cs" />
<Compile Include="Computers\Commodore64\Experimental\Chips\Internals\Vic.VideoProvider.cs" />

View File

@ -7,16 +7,25 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic
{
// inputs
public Action ClockPhi0;
public Func<int, int> ReadColorRam;
public Func<int, int> ReadRam;
// outputs
public bool AEC { get { return aec; } }
public bool BA { get { return ba; } }
public bool IRQ { get { return irq; } }
public bool OutputAEC() { return aec; }
public bool OutputBA() { return ba; }
public bool OutputIRQ() { return irq; }
// exposed internal data
public int Address { get { return address; } }
public int CharacterData { get { return characterData; } }
public int ColorData { get { return colorData; } }
public int Data { get { return data; } }
public int DataPhi1 { get { return phi1Data; } }
public int GraphicsData { get { return graphicsData; } }
}
}

View File

@ -7,78 +7,198 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic
{
class Sprite
{
public int Color;
public bool DataCollision;
public bool Enabled;
public bool ExpandX;
public bool ExpandY;
public bool Multicolor;
public bool Priority;
public bool SpriteCollision;
public int X;
public int Y;
}
int address;
bool aec;
int aecCounter;
bool ba;
int[] backgroundColor;
bool bitmapMode;
int borderColor;
bool cas;
int characterBitmap;
bool columnSelect;
int data;
bool dataCollisionInterrupt;
bool dataCollisionInterruptEnable;
bool displayEnable;
bool extraColorMode;
bool irq;
bool lightPenInterrupt;
bool lightPenInterruptEnable;
int lightPenX;
int lightPenY;
bool multiColorMode;
bool rasterInterrupt;
bool rasterInterruptEnable;
int rasterX;
int rasterY;
bool reset;
bool rowSelect;
bool spriteCollisionInterrupt;
bool spriteCollisionInterruptEnable;
int[] spriteMultiColor;
Sprite[] sprites;
int videoMemory;
int xScroll;
int yScroll;
bool badLineCondition;
bool badLineEnable;
bool idleState;
int pixelTimer;
int characterData;
int colorData;
int data;
int graphicsData;
bool mainBorder;
bool phi0;
int phi1Data;
int pixel;
int rasterX;
int refreshCounter;
int rowCounter;
bool verticalBorder;
int videoCounter;
int videoCounterBase;
int videoMatrixLineIndex;
public Vic(VicSettings settings)
{
// initialize timing values
InitTiming(settings.timing);
// calculate visible screen dimensions
screenWidth = screenXEnd - screenXStart;
screenHeight = screenYEnd - screenYStart;
if (screenXEnd < screenXStart)
screenWidth += rasterWidth;
if (screenYEnd < screenYStart)
screenHeight += rasterCount;
// reset registers
pixelBufferLength = 12;
Reset();
}
public void Clock()
{
do
{
// process horizontal triggers
if (rasterX == screenXStart)
hBlank = false;
else if (rasterX == screenXEnd)
{
hBlank = true;
rasterDelay = hBlankDelay;
}
if (rasterX == characterBAStart)
characterBA = false;
else if (rasterX == characterBAEnd)
{
characterBA = true;
graphicsFetch = false;
}
if (rasterX == characterFetchStart)
{
graphicsFetch = true;
refreshFetch = false;
}
if (rasterX == rasterWidth)
rasterX = 0;
else if (rasterX == rasterAdvance)
{
// process vertical triggers
rasterY++;
if (rasterY == screenYStart)
vBlank = false;
else if (rasterY == screenYEnd)
vBlank = 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);
}
else if (refreshFetch)
{
// covers memory refresh fetches
fetchState = phi0 ? FetchState.Refresh : FetchState.None;
}
else
{
// covers sprite pointer and data fetches
foreach (Sprite sprite in sprites)
{
if (rasterX == sprite.BAStart)
sprite.BA = false;
else if (rasterX == sprite.BAEnd)
{
sprite.BA = true;
sprite.Fetch = false;
}
if (!sprite.BA && sprite.Enabled)
{
fetchState = FetchState.Sprite;
ba = false;
break;
}
if (rasterX == sprite.FetchStart)
{
sprite.Fetch = true;
fetchState = FetchState.Pointer;
break;
}
}
}
// determine AEC state
if (ba)
{
aecCounter = 7;
aec = true;
}
else
{
if (aecCounter > 0)
aecCounter--;
else
aec = false;
}
// VIC can perform a fetch every half-cycle
switch (fetchState)
{
case FetchState.Character:
address = videoCounter | videoMemory;
colorData = ReadColorRam(address);
characterData = ReadRam(address);
data = characterData;
break;
case FetchState.Graphics:
address = (extraColorMode ? 0x39FF : 0x3FFF);
if (bitmapMode)
address &= (rowCounter | (videoCounter << 3) | (characterBitmap & 0x2000));
else
address &= (rowCounter | (data << 3) | characterBitmap);
data = ReadRam(address);
graphicsData = data;
break;
case FetchState.Idle:
address = (extraColorMode ? 0x39FF : 0x3FFF);
data = ReadRam(address);
break;
case FetchState.Pointer:
address = spriteIndex | videoMemory | 0x03F8;
data = ReadRam(address);
break;
case FetchState.Refresh:
address = refreshCounter | 0x3F00;
data = ReadRam(address);
break;
case FetchState.Sprite:
address = data | sprites[spriteIndex].Counter;
data = ReadRam(address);
break;
}
// render 4 pixels
for (int i = 0; i < 4; i++)
{
if (!hBlank && !vBlank)
{
videoBufferIndex++;
}
if (rasterDelay > 0)
rasterDelay--;
else
rasterX++;
}
phi0 = !phi0;
} while (phi0);
// at the end, clock other devices if applicable
if (pixelTimer == 0)
{
pixelTimer = 8;
ClockPhi0();
}
pixelTimer--;
}
public void Reset()
{
@ -89,6 +209,17 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
sprites[i] = new Sprite();
for (int i = 0; i < 0x40; i++)
Poke(i, 0);
phi0 = false;
// we set these so no video is displayed before
// the first frame starts
vBlank = true;
hBlank = true;
// empty out the pixel buffer
pixelBuffer = new int[pixelBufferLength];
pixelBufferIndex = 0;
borderPixelBufferIndex = 8;
}
}
}

View File

@ -7,6 +7,35 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic
{
int[] backgroundColor;
bool bitmapMode;
int borderColor;
int characterBitmap;
bool columnSelect;
bool dataCollisionInterrupt;
bool dataCollisionInterruptEnable;
bool displayEnable;
bool extraColorMode;
bool irq;
bool lightPenInterrupt;
bool lightPenInterruptEnable;
int lightPenX;
int lightPenY;
bool multiColorMode;
bool rasterInterrupt;
bool rasterInterruptEnable;
int rasterY;
bool reset;
bool rowSelect;
bool spriteCollisionInterrupt;
bool spriteCollisionInterruptEnable;
int spriteIndex;
int[] spriteMultiColor;
Sprite[] sprites;
int videoMemory;
int xScroll;
int yScroll;
public int Peek(int addr)
{
switch (addr)

View File

@ -7,5 +7,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
public class VicSettings
{
public VicTiming timing;
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic
{
sealed class Sprite
{
public bool BA;
public int BAEnd; //precalculated
public int BAStart; //precalculated
public int Counter; //MC
public int CounterBase; //MCBASE
public int Data; //24-bit shift register
public bool Fetch;
public int FetchStart; //precalculated
public int Color;
public bool DataCollision;
public bool Enabled;
public bool ExpandX;
public bool ExpandY;
public bool Multicolor;
public bool Priority;
public bool SpriteCollision;
public int X;
public int Y;
public Sprite()
{
BA = true;
}
}
}
}

View File

@ -7,44 +7,74 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic
{
protected struct CycleTiming
{
public int CharacterCycle;
public int RefreshCycle;
public int SpriteCycle;
}
protected struct DisplayTiming
{
public int CyclesPerLine;
public int HBlankStart;
public int HBlankEnd;
public int LeftXCoordinate;
public int LinesPerFrame;
public int VBlankStart;
public int VBlankEnd;
public int VisibleLines;
public int VisiblePixels;
}
protected class VicTiming
{
public CycleTiming Cycle;
public DisplayTiming Display;
}
enum FetchState
{
None,
Idle,
Graphics,
Color,
Character,
Refresh,
Sprite,
Pointer
}
FetchState fetchState;
int characterCycleCount;
int refreshCycleCount;
int spriteCycleCount;
bool characterBA;
int characterBAEnd;
int characterBAStart;
bool characterFetch;
int characterFetchStart;
bool graphicsFetch;
bool hBlank;
int hBlankDelay;
int rasterAdvance;
int rasterCount;
int rasterDelay;
int rasterWidth;
bool refreshFetch;
int refreshStart;
int screenXEnd;
int screenXStart;
int screenYEnd;
int screenYStart;
bool vBlank;
void InitTiming(VicTiming timing)
{
int spriteBAStart = timing.SpriteBAStart;
for (int i = 0; i < 8; i++)
{
sprites[i].BAStart = spriteBAStart % timing.HSize;
sprites[i].BAEnd = (spriteBAStart + 40) % timing.HSize;
sprites[i].FetchStart = (spriteBAStart + 24) % timing.HSize;
}
characterBAStart = timing.CharacterBAStart % timing.HSize;
characterBAEnd = (characterBAStart + 344) % timing.HSize;
characterFetchStart = (characterFetchStart + 24) % timing.HSize;
screenXStart = timing.HBlankEnd;
screenXEnd = timing.HBlankStart;
screenYStart = timing.VBlankEnd;
screenYEnd = timing.VBlankStart;
rasterWidth = timing.HSize;
rasterAdvance = timing.LineStart;
rasterCount = timing.VSize;
}
}
sealed public class VicTiming
{
public int CharacterBAStart; //VMBA
public int HBlankDelay;
public int HBlankEnd; //HBLANK
public int HBlankStart; //HBLANK
public int HSize; //BOL
public int LineStart; //VINC
public int RefreshStart; //REFW
public int SpriteBAStart; //SPBA
public int VBlankEnd; //VBLANK
public int VBlankStart; //VBLANK
public int VSize; //VRESET
}
}

View File

@ -7,31 +7,59 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic : IVideoProvider
{
protected int[] videoBuffer;
int borderPixelBufferIndex;
int[] pixelBuffer;
int pixelBufferIndex;
int pixelBufferLength;
int screenHeight;
int screenWidth;
int[] videoBuffer;
int videoBufferIndex;
// palette
static private int[] palette =
{
Colors.ARGB(0x00, 0x00, 0x00),
Colors.ARGB(0xFF, 0xFF, 0xFF),
Colors.ARGB(0x68, 0x37, 0x2B),
Colors.ARGB(0x70, 0xA4, 0xB2),
Colors.ARGB(0x6F, 0x3D, 0x86),
Colors.ARGB(0x58, 0x8D, 0x43),
Colors.ARGB(0x35, 0x28, 0x79),
Colors.ARGB(0xB8, 0xC7, 0x6F),
Colors.ARGB(0x6F, 0x4F, 0x25),
Colors.ARGB(0x43, 0x39, 0x00),
Colors.ARGB(0x9A, 0x67, 0x59),
Colors.ARGB(0x44, 0x44, 0x44),
Colors.ARGB(0x6C, 0x6C, 0x6C),
Colors.ARGB(0x9A, 0xD2, 0x84),
Colors.ARGB(0x6C, 0x5E, 0xB5),
Colors.ARGB(0x95, 0x95, 0x95)
};
public int[] GetVideoBuffer()
{
throw new NotImplementedException();
return videoBuffer;
}
public int VirtualWidth
{
get { throw new NotImplementedException(); }
get { return screenWidth; }
}
public int BufferWidth
{
get { throw new NotImplementedException(); }
get { return screenWidth; }
}
public int BufferHeight
{
get { throw new NotImplementedException(); }
get { return screenHeight; }
}
public int BackgroundColor
{
get { throw new NotImplementedException(); }
get { return palette[0]; }
}
}
}