public void Step(int previousInstructionCycles) { ModeClock += previousInstructionCycles; switch (Mode) { case GPUModes.HBlank: if (ModeClock >= 204) { ModeClock = 0; CurrentLine++; if (CurrentLine == 143) { Mode = GPUModes.VBlank; // WRITE TO THE SCREEN HERE } else { Mode = GPUModes.ScanlineOAMRead; } } break; case GPUModes.VBlank: if (ModeClock >= 456) { ModeClock = 0; CurrentLine++; if (CurrentLine > 153) { Mode = GPUModes.ScanlineOAMRead; CurrentLine = 0; } } break; case GPUModes.ScanlineOAMRead: if (ModeClock >= 80) { ModeClock = 0; Mode = GPUModes.ScanlineVRAMRead; } break; case GPUModes.ScanlineVRAMRead: if (ModeClock >= 172) { ModeClock = 0; Mode = GPUModes.HBlank; // WRITE THE SCANLINE HERE } break; } }
public void Reset() { modeClocks = 0; scrollX = 0; scrollY = 0; winX = 0; winY = 0; line = 0; mode = GPUModes.OAM_READ; tileSet = new GPUTile[512]; for (var i = 0; i < 512; i++) { tileSet[i] = new GPUTile(); } VRamBuffer = new Color[256 * 256]; for (var i = 0; i < 256 * 256; i++) { VRamBuffer[i] = Color.White; } oam = new byte[160]; switchLCD = true; switchBg = false; switchWin = false; objSize = false; objs = new GPUObject[40]; prioObjects = new GPUObject[40]; for (var i = 0; i < 40; i++) { objs[i] = new GPUObject { Pos = i, Y = -16, X = -8, Tile = 0, Palette = 0, YFlip = false, XFlip = false }; prioObjects[i] = objs[i]; } switchObj = false; lineCompare = 0; lcdStat = 0; interruptsFired = 0; bgTileBase = 0x0000; bgMapBase = 0x1800; winMapBase = 0x1800; }
public void Cycle() { // if (!switchLCD) return; modeClocks += cpu.reg.lastClockM; switch (mode) { case GPUModes.HBLANK: if (modeClocks >= HorizontalBlankCycles) { modeClocks = 0; line++; if (line == 144) { mode = GPUModes.VBLANK; cpu.reg.TriggerInterrupts |= Flags.INT_VBLANK; if (FlagVBlankMode && cpu.reg.InterruptEnable) { cpu.reg.TriggerInterrupts |= Flags.INT_LCDSTAT; } } else { mode = GPUModes.OAM_READ; if (FlagOamMode && cpu.reg.InterruptEnable) { cpu.reg.TriggerInterrupts |= Flags.INT_LCDSTAT; } } if (line == lineCompare && FlagLycLy && cpu.reg.InterruptEnable) { cpu.reg.TriggerInterrupts |= Flags.INT_LCDSTAT; } } break; case GPUModes.VBLANK: if (modeClocks >= (VerticalBlankCycles / 9)) { modeClocks = 0; line++; if (line == lineCompare && FlagLycLy) { cpu.reg.TriggerInterrupts |= Flags.INT_LCDSTAT; } if (line > 153) { mode = GPUModes.OAM_READ; line = 0; if (FlagOamMode && cpu.reg.InterruptEnable) { cpu.reg.TriggerInterrupts |= Flags.INT_LCDSTAT; } } } break; case GPUModes.OAM_READ: if (modeClocks >= OamCycles) { modeClocks = 0; mode = GPUModes.VRAM_READ; } break; case GPUModes.VRAM_READ: if (modeClocks >= VRamCycles) { modeClocks = 0; RenderScanline(); mode = GPUModes.HBLANK; // TODO: DMA if (FlagHBlankMode && cpu.reg.InterruptEnable) { cpu.reg.TriggerInterrupts |= Flags.INT_LCDSTAT; } } break; default: Console.WriteLine($"BUG! Went to a unknown state: {mode}"); break; } }