Commodore64: Experimental VIC updated.
This commit is contained in:
parent
6b454f3a78
commit
c827d42f2d
|
@ -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" />
|
||||
|
|
|
@ -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; } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -7,5 +7,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.Experimental.Chips.Internals
|
|||
{
|
||||
public class VicSettings
|
||||
{
|
||||
public VicTiming timing;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue