public void ExecFrame(bool render) { // Determine the effective priority mode. if (Window1Width < 0x40 && Window2Width < 0x40) { EffectivePriorityMode = PriorityModeSlot3 >> 2; } else if (Window2Width > 512) { EffectivePriorityMode = PriorityModeSlot1 >> 2; } else { Console.WriteLine("Unsupported VPC window settings"); EffectivePriorityMode = 0; } // Latch frame dimensions and framebuffer, for purely dumb reasons FrameWidth = VDC1.BufferWidth; FrameHeight = VDC1.BufferHeight; FrameBuffer = VDC1.GetVideoBuffer(); int ScanLine = 0; int ActiveDisplayStartLine = VDC1.DisplayStartLine; while (true) { VDC1.ScanLine = ScanLine; VDC2.ScanLine = ScanLine; int VBlankLine = ActiveDisplayStartLine + VDC1.Registers[VDW] + 1; if (VBlankLine > 261) { VBlankLine = 261; } VDC1.ActiveLine = ScanLine - ActiveDisplayStartLine; VDC2.ActiveLine = VDC1.ActiveLine; bool InActiveDisplay = (ScanLine >= ActiveDisplayStartLine) && (ScanLine < VBlankLine); if (ScanLine == ActiveDisplayStartLine) { VDC1.RCRCounter = 0x40; VDC2.RCRCounter = 0x40; } if (ScanLine == VBlankLine) { VDC1.UpdateSpriteAttributeTable(); VDC2.UpdateSpriteAttributeTable(); } if (VDC1.RCRCounter == (VDC1.Registers[RCR] & 0x3FF)) { if (VDC1.RasterCompareInterruptEnabled) { VDC1.StatusByte |= VDC.StatusRasterCompare; CPU.IRQ1Assert = true; } } if (VDC2.RCRCounter == (VDC2.Registers[RCR] & 0x3FF)) { if (VDC2.RasterCompareInterruptEnabled) { VDC2.StatusByte |= VDC.StatusRasterCompare; CPU.IRQ1Assert = true; } } CPU.Execute(24); if (InActiveDisplay) { if (ScanLine == ActiveDisplayStartLine) { VDC1.BackgroundY = VDC1.Registers[BYR]; VDC2.BackgroundY = VDC2.Registers[BYR]; } else { VDC1.BackgroundY++; VDC1.BackgroundY &= 0x01FF; VDC2.BackgroundY++; VDC2.BackgroundY &= 0x01FF; } } CPU.Execute(VDC1.HBlankCycles - 24); if (InActiveDisplay) { if (render) { RenderScanLine(); } } if (ScanLine == VBlankLine && VDC1.VBlankInterruptEnabled) { VDC1.StatusByte |= VDC.StatusVerticalBlanking; } if (ScanLine == VBlankLine && VDC2.VBlankInterruptEnabled) { VDC2.StatusByte |= VDC.StatusVerticalBlanking; } if (ScanLine == VBlankLine + 4 && VDC1.SatDmaPerformed) { VDC1.SatDmaPerformed = false; if ((VDC1.Registers[DCR] & 1) > 0) { VDC1.StatusByte |= VDC.StatusVramSatDmaComplete; } } if (ScanLine == VBlankLine + 4 && VDC2.SatDmaPerformed) { VDC2.SatDmaPerformed = false; if ((VDC2.Registers[DCR] & 1) > 0) { VDC2.StatusByte |= VDC.StatusVramSatDmaComplete; } } CPU.Execute(2); if ((VDC1.StatusByte & (VDC.StatusVerticalBlanking | VDC.StatusVramSatDmaComplete)) != 0) { CPU.IRQ1Assert = true; } if ((VDC2.StatusByte & (VDC.StatusVerticalBlanking | VDC.StatusVramSatDmaComplete)) != 0) { CPU.IRQ1Assert = true; } CPU.Execute(455 - VDC1.HBlankCycles - 2); if (InActiveDisplay == false && VDC1.DmaRequested) { VDC1.RunDmaForScanline(); } if (InActiveDisplay == false && VDC2.DmaRequested) { VDC2.RunDmaForScanline(); } VDC1.RCRCounter++; VDC2.RCRCounter++; ScanLine++; if (ScanLine == VCE.NumberOfScanlines) { break; } } }