BizHawk/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Vic.Parse.cs

271 lines
7.2 KiB
C#

namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
public sealed partial class Vic
{
private const int BaResetCounter = 4;
private const int PipelineUpdateVc = 0x00000001; // vc/rc rule 2
private const int PipelineSpriteCrunch = 0x00000002;
private const int PipelineUpdateMcBase = 0x00000004;
private const int PipelineBorderLeft1 = 0x00000008;
private const int PipelineBorderLeft0 = 0x00000010;
private const int PipelineSpriteDma = 0x00000020; // sprite rule 3
private const int PipelineBorderRight0 = 0x00000040;
private const int PipelineSpriteExpansion = 0x00000080; // sprite rule 2
private const int PipelineBorderRight1 = 0x00000100;
private const int PipelineSpriteDisplay = 0x00000200; // sprite rule 4
private const int PipelineUpdateRc = 0x00000400; // vc/rc rule 5
private const int PipelineHoldX = 0x40000000;
private const int RasterIrqLine0Cycle = 2;
private const int RasterIrqLineXCycle = 1;
private const int FetchTypeSprite = 0x0000;
private const int FetchTypeRefresh = 0x0100;
private const int FetchTypeColor = 0x0200;
private const int FetchTypeGraphics = 0x0300;
private const int FetchTypeIdle = 0x0400;
private const int FetchTypeNone = 0x0500;
private const int BaTypeNone = 0x0888;
private const int BaTypeCharacter = 0x1000;
private const int BaTypeMaskSprite0 = 0x000F;
private const int BaTypeMaskSprite1 = 0x00F0;
private const int BaTypeMaskSprite2 = 0x0F00;
private const int AddressMask = 0x3FFF;
private const int AddressMaskEc = 0x39FF;
private const int AddressMaskRefresh = 0x3F00;
private int _parseAddr;
private int _parseCycleBaSprite0;
private int _parseCycleBaSprite1;
private int _parseCycleBaSprite2;
private int _parseCycleFetchSpriteIndex;
private int _parseFetch;
private int _parseFetchType;
private int _parseBa;
private int _parseAct;
private bool _parseIsSprCrunch;
private void ParseCycle()
{
// initialization
_parseAddr = AddressMask;
_parseFetch = _fetchPipeline[_cycleIndex];
_parseBa = _baPipeline[_cycleIndex];
_parseAct = _actPipeline[_cycleIndex];
// apply X location
_rasterX = _rasterXPipeline[_cycleIndex];
_rasterXHold = (_parseAct & PipelineHoldX) != 0;
// perform fetch
_parseFetchType = _parseFetch & 0xFF00;
switch (_parseFetchType)
{
case FetchTypeColor:
// fetch C
if (!_idle)
{
if (_badline)
{
_parseAddr = _pointerVm | _vc;
_dataC = ReadMemory(_parseAddr);
_dataC |= (ReadColorRam(_parseAddr) & 0xF) << 8;
_bufferC[_vmli] = _dataC;
}
else
{
_dataC = _bufferC[_vmli];
}
}
else
{
_dataC = 0;
_bufferC[_vmli] = _dataC;
}
_srColorSync |= 0x01 << (7 - _xScroll);
break;
case FetchTypeGraphics:
// fetch G
if (!_idle)
{
if (_bitmapMode)
_parseAddr = _rc | (_vc << 3) | ((_pointerCb & 0x4) << 11);
else
_parseAddr = _rc | ((_dataC & 0xFF) << 3) | (_pointerCb << 11);
}
if (_extraColorModeBuffer)
_parseAddr &= AddressMaskEc;
_dataG = ReadMemory(_parseAddr);
_sr |= _dataG << (7 - _xScroll);
_srSync |= 0xAA << (7 - _xScroll);
if (!_idle)
{
_bufferG[_vmli] = _dataG;
_vmli = (_vmli + 1) & 0x3F;
_vc = (_vc + 1) & 0x3FF;
}
break;
case FetchTypeNone:
// fetch none
break;
case FetchTypeRefresh:
// fetch R
_refreshCounter = (_refreshCounter - 1) & 0xFF;
_parseAddr = AddressMaskRefresh | _refreshCounter;
ReadMemory(_parseAddr);
break;
case FetchTypeIdle:
// fetch I
ReadMemory(AddressMask);
break;
default:
_parseCycleFetchSpriteIndex = _parseFetch & 0x7;
if ((_parseFetch & 0xF0) == 0) // sprite rule 5
{
// fetch P
_parseAddr = 0x3F8 | _pointerVm | _parseCycleFetchSpriteIndex;
_sprites[_parseCycleFetchSpriteIndex].Pointer = ReadMemory(_parseAddr);
_sprites[_parseCycleFetchSpriteIndex].ShiftEnable = false;
}
else
{
// fetch S
var spr = _sprites[_parseCycleFetchSpriteIndex];
if (spr.Dma)
{
_parseAddr = spr.Mc | (spr.Pointer << 6);
spr.Sr |= ReadMemory(_parseAddr) << ((0x30 - (_parseFetch & 0x30)) >> 1);
spr.Mc++;
spr.Loaded |= 0x800000;
}
else if ((_parseFetch & 0xF0) == 0x20)
{
ReadMemory(AddressMask);
}
}
break;
}
// perform actions
_borderCheckLEnable = (_parseAct & (PipelineBorderLeft0 | PipelineBorderLeft1)) != 0;
_borderCheckREnable = (_parseAct & (PipelineBorderRight0 | PipelineBorderRight1)) != 0;
foreach (var spr in _sprites) // sprite rule 1
{
if (!spr.YExpand)
{
spr.YCrunch = true;
}
}
if ((_parseAct & PipelineUpdateMcBase) != 0) // VIC addendum sprite rule 7
{
foreach (var spr in _sprites)
{
if (spr.YCrunch)
{
spr.Mcbase = spr.Mc;
if (spr.Mcbase == 63)
{
spr.Dma = false;
}
}
}
}
if ((_parseAct & PipelineSpriteDma) != 0) // sprite rule 3
{
foreach (var spr in _sprites)
{
if (spr.Enable && spr.Y == (_rasterLine & 0xFF) && !spr.Dma)
{
spr.Dma = true;
spr.Mcbase = 0;
spr.YCrunch = true;
}
}
}
if ((_parseAct & PipelineSpriteExpansion) != 0) // sprite rule 2
{
foreach (var spr in _sprites)
{
if (spr.Dma && spr.YExpand)
{
spr.YCrunch ^= true;
}
}
}
if ((_parseAct & PipelineSpriteDisplay) != 0) // VIC addendum on sprite rule 4
{
foreach (var spr in _sprites)
{
spr.Mc = spr.Mcbase;
if (spr.Dma)
{
if (spr.Enable && spr.Y == (_rasterLine & 0xFF))
{
spr.Display = true;
}
}
else
{
spr.Display = false;
}
}
}
_parseIsSprCrunch = (_parseAct & PipelineSpriteCrunch) != 0; // VIC addendum sprite rule 7
if ((_parseAct & PipelineUpdateVc) != 0) // VC/RC rule 2
{
_vc = _vcbase;
_srColorIndexLatch = 0;
_vmli = 0;
if (_badline)
{
_rc = 0;
}
}
if ((_parseAct & PipelineUpdateRc) != 0) // VC/RC rule 5
{
if (_rc == 7)
{
_idle = true;
_vcbase = _vc;
}
if (!_idle || _badline)
{
_rc = (_rc + 1) & 0x7;
_idle = false;
}
}
// perform BA flag manipulation
_pinBa = true;
switch (_parseBa)
{
case BaTypeNone:
break;
case BaTypeCharacter:
_pinBa = !_badline;
break;
default:
_parseCycleBaSprite0 = _parseBa & BaTypeMaskSprite0;
_parseCycleBaSprite1 = (_parseBa & BaTypeMaskSprite1) >> 4;
_parseCycleBaSprite2 = (_parseBa & BaTypeMaskSprite2) >> 8;
if ((_parseCycleBaSprite0 < 8 && _sprites[_parseCycleBaSprite0].Dma) ||
(_parseCycleBaSprite1 < 8 && _sprites[_parseCycleBaSprite1].Dma) ||
(_parseCycleBaSprite2 < 8 && _sprites[_parseCycleBaSprite2].Dma))
_pinBa = false;
break;
}
_cycleIndex++;
}
}
}