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]; } } } }