diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 5902044d52..3bd0deadd4 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -113,6 +113,7 @@
+
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Interface.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Interface.cs
index 4155df0585..c2f33d5b5b 100644
--- a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Interface.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Interface.cs
@@ -7,16 +7,25 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
sealed public partial class Vic
{
+ // inputs
public Action ClockPhi0;
public Func ReadColorRam;
public Func 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; } }
}
}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Internal.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Internal.cs
index b91dbca57a..12609363e8 100644
--- a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Internal.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Internal.cs
@@ -7,77 +7,197 @@ 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--;
+ ClockPhi0();
}
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;
}
}
}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Registers.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Registers.cs
index 4c19e7a007..c6eb00d434 100644
--- a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Registers.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Registers.cs
@@ -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)
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Settings.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Settings.cs
index 58b8e5d909..1c038d036e 100644
--- a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Settings.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Settings.cs
@@ -7,5 +7,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
{
public class VicSettings
{
+ public VicTiming timing;
}
}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Sprite.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Sprite.cs
new file mode 100644
index 0000000000..35509357c0
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Sprite.cs
@@ -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;
+ }
+ }
+
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Timing.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Timing.cs
index d3049af745..4ee763bae0 100644
--- a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Timing.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.Timing.cs
@@ -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
}
}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.VideoProvider.cs b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.VideoProvider.cs
index a40d194cdd..c23fe31a98 100644
--- a/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.VideoProvider.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/Experimental/Chips/Internals/Vic.VideoProvider.cs
@@ -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]; }
}
}
}