using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { sealed public partial class Vic { const int baResetCounter = 7; const int pipelineUpdateVc = 1; const int pipelineChkSprCrunch = 2; const int pipelineUpdateMcBase = 4; const int pipelineChkBrdL1 = 8; const int pipelineChkBrdL0 = 16; const int pipelineChkSprDma = 32; const int pipelineChkBrdR0 = 64; const int pipelineChkSprExp = 128; const int pipelineChkBrdR1 = 256; const int pipelineChkSprDisp = 512; const int pipelineUpdateRc = 1024; const int pipelineHBlankL = 0x10000000; const int pipelineHBlankR = 0x20000000; const int pipelineHoldX = 0x40000000; const int rasterIrqLine0Cycle = 1; const int rasterIrqLineXCycle = 0; 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 void ParseCycle() { parseaddr = 0x3FFF; parsefetch = pipeline[1][cycleIndex]; parseba = pipeline[2][cycleIndex]; parseact = pipeline[3][cycleIndex]; // apply X location rasterX = pipeline[0][cycleIndex]; rasterXHold = ((parseact & pipelineHoldX) != 0); // perform fetch parsefetchType = parsefetch & 0xFF00; if (parsefetchType == 0x100) { // fetch R refreshCounter = (refreshCounter - 1) & 0xFF; parseaddr = (0x3F00 | refreshCounter); ReadMemory(parseaddr); } else if (parsefetchType == 0x200) { delayC = xScroll; if (!idle) { if (badline) { parseaddr = (pointerVM | vc); dataC = ReadMemory(parseaddr); dataC |= ((int)ReadColorRam(parseaddr) & 0xF) << 8; bufferC[vmli] = dataC; } else { dataC = bufferC[vmli]; } } else { dataC = 0; bufferC[vmli] = dataC; } srC <<= 12; srC |= dataC; } else if (parsefetchType == 0x300) { // fetch G if (idle) parseaddr = 0x3FFF; else { if (bitmapMode) parseaddr = (rc | (vc << 3) | ((pointerCB & 0x4) << 11)); else parseaddr = (rc | ((dataC & 0xFF) << 3) | (pointerCB << 11)); } if (extraColorMode) parseaddr &= 0x39FF; dataG = ReadMemory(parseaddr); sr |= dataG << (7 - xScroll); srSync |= 0xAA << (7 - xScroll); if (!idle) { bufferG[vmli] = dataG; vmli = (vmli + 1) & 0x3F; vc = (vc + 1) & 0x3FF; } } else if (parsefetchType == 0x400) { // fetch I parseaddr = (extraColorMode ? 0x39FF : 0x3FFF); dataG = ReadMemory(parseaddr); } else if (parsefetchType == 0x500) { // fetch none } else { 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 |= (int)(ReadMemory(parseaddr)) << ((0x30 - (parsefetch & 0x30)) >> 1); spr.mc++; spr.loaded |= 0x800000; } } } // perform BA flag manipulation if (parseba == 0x0000) { pinBA = true; } else if (parseba == 0x1000) { pinBA = !badline; } else { parsecycleBAsprite0 = (parseba & 0x000F); parsecycleBAsprite1 = (parseba & 0x00F0) >> 4; parsecycleBAsprite2 = (parseba & 0x0F00) >> 8; if ((parsecycleBAsprite0 < 8 && sprites[parsecycleBAsprite0].dma) || (parsecycleBAsprite1 < 8 && sprites[parsecycleBAsprite1].dma) || (parsecycleBAsprite2 < 8 && sprites[parsecycleBAsprite2].dma)) pinBA = false; else pinBA = true; } // perform actions borderCheckLEnable = ((parseact & (pipelineChkBrdL0 | pipelineChkBrdL1)) != 0); borderCheckREnable = ((parseact & (pipelineChkBrdR0 | pipelineChkBrdR1)) != 0); hblankCheckEnableL = ((parseact & pipelineHBlankL) != 0); hblankCheckEnableR = ((parseact & pipelineHBlankR) != 0); foreach (var spr in sprites) { if (!spr.yExpand) spr.yCrunch = true; } if ((parseact & pipelineChkSprExp) != 0) { foreach (var spr in sprites) { if (spr.yExpand) spr.yCrunch ^= true; } } if ((parseact & pipelineChkSprDma) != 0) { foreach (var spr in sprites) { if (spr.enable && spr.y == (rasterLine & 0xFF) && !spr.dma) { spr.dma = true; spr.mcbase = 0; spr.yCrunch = !spr.yExpand; } } } if ((parseact & pipelineChkSprDisp) != 0) { foreach (var spr in sprites) { spr.mc = spr.mcbase; if (spr.dma && spr.y == (rasterLine & 0xFF)) { spr.display = true; } else if (!spr.dma) { spr.display = false; } } } if ((parseact & pipelineChkSprCrunch) != 0) { // not sure if anything has to go here, // some sources say yes, some say no... } if ((parseact & pipelineUpdateMcBase) != 0) { foreach (var spr in sprites) { if (spr.yCrunch) { spr.mcbase = spr.mc; if (spr.mcbase == 63) { if (!spr.yCrunch) { } spr.dma = false; } } } } if ((parseact & pipelineUpdateRc) != 0) // VC/RC rule 5 { if (rc == 7) { idle = true; vcbase = vc; } if (!idle) rc = (rc + 1) & 0x7; } if ((parseact & pipelineUpdateVc) != 0) // VC/RC rule 2 { vc = vcbase; vmli = 0; if (badline) rc = 0; } cycleIndex++; } } }