diff --git a/BizHawk.Emulation/Consoles/PC Engine/Compat.txt b/BizHawk.Emulation/Consoles/PC Engine/Compat.txt index c993b1fd03..7b08eaac0d 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/Compat.txt +++ b/BizHawk.Emulation/Consoles/PC Engine/Compat.txt @@ -9,44 +9,41 @@ General: Right now the emulator is simply displaying a framebuffer. Eventually, we will do an update that emulates NTSC. But for now we're letting this be. There's no intermediate step between emulating a framebuffer and emulating a TV. -Air Zonk - Seems OK now - previous problem game -Battle Ace - Some gfx glitches -Cadash - Minor raster issue. Timing sensitive game. +Air Zonk - OK now - previous problem game +Cadash - Req HBlank hack to eliminate minor visual artifact Chase HQ - Press start -"O" sprite gets left on screen. probably timing on SATB DMA -Coryoon - Seems OK now - previous problem game +Coryoon - OK now - previous problem game Cross Wiber - Minor; Raster on wrong line -Davis Cup Tennis - Some timing issue, splash screen is too slow -Dungeon Explorer - Seems OK now - previous problem game -Legend of Hero Ton- Slight gfx- check top of screen -Lode Runner - Seems OK now - previous problem game -Madoo Granzort - Graphics issues because SGX VPC renderer is not using new frame timing +Dungeon Explorer - OK now - previous problem game +Lode Runner - OK now - previous problem game MML Demo - Echo channels are too loud (equal volume!) -Outrun - Seems OK now - previous problem game -Power Drift - Timing glitch... starting new game runs slower than it should -Power Tennis - Elaborate intro screen doesnt display right -Sinistron - Much less bad raster effect errors now +Outrun - Req HBlank hack to eliminate visual artifact Tiger Road - On second level, sprites should be getting masked from the top status area somehow =================================== Games that need TV Emulation (to varying degrees) =================================== +Greater degrees: + Final Blaster - Intro does crazy shit with video modes; not sure what if anything to do about it Griffon - Screen goes black because game changes video mode mid-frame -=================================== -Games with 'Frame Too Tall' issues: -=================================== +Lesser degrees: Aero Blaster - Bottom of Screen extends too many lines - like 3 extra or so Alice - Screen too tall; glitches when scrolling up, but in pcejin also, but not ootake; ergo probably a timing artifact Dead Moon - Screen is too tall Jack Nicholas Golf- Some screens are too tall and reveal bad gfx below the intended visible screen +Legend of Hero Ton- Slight gfx issue on top of screen +Madoo Granzort - Screen ~5 pixels too tall Metal Stoker - Tearing when scrolling vertically at bottom of screen - screen too tall? Side Arms - Screen is like 4 pixels too tall +=================================== Stuff I Fixed That's Not In Other Docs: +=================================== + Street Fighter II special mapper + Populous has special SaveRAM, 32k starting at page $40. @@ -63,4 +60,4 @@ Stuff I Fixed That's Not In Other Docs: 4 color modes. It appears to be the only game that requires this, and it's a shitty game. :( + The ROM of Paranoia (J) that is commonly labeled as the authoritative dump - I assume its a bad dump, because it dies during the 3rd stage on ALL EMULATORS. Alternative versions of the rom - work fine. \ No newline at end of file + work fine. \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs index 1cba9724c2..9592d3a6ea 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs @@ -120,6 +120,18 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx Cpu.WriteMemory21 = WriteMemoryPopulous; } + // Ok, yes, HBlankPeriod's only purpose is game-specific hax. + // 1) At least they're not coded directly into the emulator, but instead data-driven. + // 2) The games (2) which have custom HBlankPeriods work without it, the override only + // serves to clean up minor gfx anomalies. + // 3) There's no point in haxing the timing with incorrect values in an attempt to avoid this. + // The proper fix is cycle-accurate/bus-accurate timing. That isn't coming to the C# + // version of this core. Lets just acknolwedge that the timing is imperfect and fix + // it in the least intrusive and most honest way we can. + + if (game.GetOptions().ContainsStartsWith("HBlankPeriod")) + VDC1.HBlankCycles = int.Parse(game.GetOptions().GetOptionValue("HBlankPeriod")); + Cpu.ResetPC(); SetupMemoryDomains(); } @@ -139,7 +151,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx PSG.BeginFrame(Cpu.TotalExecutedCycles); if (SuperGrafx) - VPC.ExecFrame(); // TODO supergrafx frameskipping (waiting on a larger update of VPC frame timing, once I get VDC timing correct) + VPC.ExecFrame(render); else VDC1.ExecFrame(render); diff --git a/BizHawk.Emulation/Consoles/PC Engine/VDC.Render.cs b/BizHawk.Emulation/Consoles/PC Engine/VDC.Render.cs index 01654a6148..025811d308 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/VDC.Render.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/VDC.Render.cs @@ -21,10 +21,11 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public int ScanLine; public int BackgroundY; public int RCRCounter; - private int ActiveLine; + public int ActiveLine; private byte[] PriorityBuffer = new byte[512]; private byte[] InterSpritePriorityBuffer = new byte[512]; + public int HBlankCycles = 79; public void ExecFrame(bool render) { @@ -40,8 +41,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx if (ScanLine == ActiveDisplayStartLine) RCRCounter = 0x40; - const int hblankCycles = 79; - if (ScanLine == VBlankLine) UpdateSpriteAttributeTable(); @@ -54,7 +53,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx } } - cpu.Execute(hblankCycles); + cpu.Execute(HBlankCycles); if (InActiveDisplay) { @@ -83,7 +82,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx if ((StatusByte & (StatusVerticalBlanking | StatusVramSatDmaComplete)) != 0) cpu.IRQ1Assert = true; - cpu.Execute(455 - hblankCycles - 2); + cpu.Execute(455 - HBlankCycles - 2); if (InActiveDisplay == false && DmaRequested) RunDmaForScanline(); diff --git a/BizHawk.Emulation/Consoles/PC Engine/VPC.cs b/BizHawk.Emulation/Consoles/PC Engine/VPC.cs index 5fb51e73b0..130207c606 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/VPC.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/VPC.cs @@ -10,10 +10,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx // Responsible for merging VDC1 and VDC2 data on the SuperGrafx. // Pretty much all documentation on the SuperGrafx courtesy of Charles MacDonald. - // VPC Frame timing has not been updated with new stuff. I expect Madoo Granzort to be fixed once the timing is updated. - // However, 1) The new frame timing is not working 100% yet, 2) I haven't decided if I want to continue having separate - // rendering in the VPC and the VDC. - public sealed class VPC : IVideoProvider { public VDC VDC1; @@ -87,6 +83,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public void LoadStateBinary(BinaryReader reader) { Registers = reader.ReadBytes(7); + WriteVPC(0x0E, Registers[6]); } public void SaveStateText(TextWriter writer) @@ -109,14 +106,19 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx else Console.WriteLine("Skipping unrecognized identifier " + args[0]); } + WriteVPC(0x0E, Registers[6]); } // We use a single priority mode for the whole frame. // No commercial SGX games really use the 'window' features AFAIK. // And there are no homebrew SGX games I know of. + // Maybe we'll emulate it in the native-code version. + private const int RCR = 6; private const int BXR = 7; private const int BYR = 8; + private const int VDW = 13; + private const int DCR = 15; private int EffectivePriorityMode = 0; @@ -127,7 +129,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx private byte[] PriorityBuffer = new byte[512]; private byte[] InterSpritePriorityBuffer = new byte[512]; - public void ExecFrame() + public void ExecFrame(bool render) { // Determine the effective priority mode. if (Window1Width < 0x40 && Window2Width < 0x40) @@ -145,12 +147,33 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx FrameHeight = VDC1.BufferHeight; FrameBuffer = VDC1.GetVideoBuffer(); - for (int ScanLine = 0; ScanLine < 262; ScanLine++) + int ScanLine = 0; + while (true) { VDC1.ScanLine = ScanLine; VDC2.ScanLine = ScanLine; - if ((ScanLine + 64) == (VDC1.Registers[6] & 0x3FF)) + int ActiveDisplayStartLine = VDC1.DisplayStartLine; + 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) { @@ -159,7 +182,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx } } - if ((ScanLine + 64) == (VDC2.Registers[6] & 0x3FF)) + if (VDC2.RCRCounter == (VDC2.Registers[RCR] & 0x3FF)) { if (VDC2.RasterCompareInterruptEnabled) { @@ -168,34 +191,76 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx } } - if (ScanLine == 240 && VDC1.VBlankInterruptEnabled) + CPU.Execute(VDC1.HBlankCycles); + + 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; + } + if (render) RenderScanLine(); + } + + if (ScanLine == VBlankLine && VDC1.VBlankInterruptEnabled) VDC1.StatusByte |= VDC.StatusVerticalBlanking; - CPU.IRQ1Assert = true; - } - if (ScanLine == 240 && VDC2.VBlankInterruptEnabled) - { + if (ScanLine == VBlankLine && VDC2.VBlankInterruptEnabled) VDC2.StatusByte |= VDC.StatusVerticalBlanking; - CPU.IRQ1Assert = true; + + if (ScanLine == VBlankLine + 4 && VDC1.SatDmaPerformed) + { + VDC1.SatDmaPerformed = false; + if ((VDC1.Registers[DCR] & 1) > 0) + VDC1.StatusByte |= VDC.StatusVramSatDmaComplete; } - CPU.Execute(455); + if (ScanLine == VBlankLine + 4 && VDC2.SatDmaPerformed) + { + VDC2.SatDmaPerformed = false; + if ((VDC2.Registers[DCR] & 1) > 0) + VDC2.StatusByte |= VDC.StatusVramSatDmaComplete; + } - if (ScanLine < FrameHeight) - RenderScanLine(); + 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; } } private void RenderScanLine() { - if (VDC1.ScanLine == 0) - { - VDC1.BackgroundY = VDC1.Registers[BYR]; - VDC2.BackgroundY = VDC2.Registers[BYR]; - } + if (VDC1.ActiveLine >= FrameHeight) + return; - InitializeScanLine(VDC1.ScanLine); + InitializeScanLine(VDC1.ActiveLine); switch (EffectivePriorityMode) { @@ -212,12 +277,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx RenderSpritesScanline(VDC2, 1, 13); break; } - - if (VDC1.ScanLine == FrameHeight - 1) - { - VDC1.UpdateSpriteAttributeTable(); - VDC2.UpdateSpriteAttributeTable(); - } } private void InitializeScanLine(int scanline) @@ -233,18 +292,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx private void RenderBackgroundScanline(VDC vdc, byte priority) { if (vdc.BackgroundEnabled == false) - { - vdc.BackgroundY++; - vdc.BackgroundY &= 0x01FF; return; - } int vertLine = vdc.BackgroundY; vertLine %= vdc.BatHeight * 8; int yTile = (vertLine / 8); int yOfs = vertLine % 8; - vdc.BackgroundY++; - vdc.BackgroundY &= 0x01FF; int xScroll = vdc.Registers[BXR] & 0x3FF; for (int x = 0; x < FrameWidth; x++) @@ -259,7 +312,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx byte c = vdc.PatternBuffer[(tileNo * 64) + (yOfs * 8) + xOfs]; if (c != 0) { - FrameBuffer[(vdc.ScanLine * FrameWidth) + x] = VCE.Palette[paletteBase + c]; + FrameBuffer[(vdc.ActiveLine * FrameWidth) + x] = VCE.Palette[paletteBase + c]; PriorityBuffer[x] = priority; } } @@ -282,7 +335,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx ushort flags = vdc.SpriteAttributeTable[(i * 4) + 3]; int height = heightTable[(flags >> 12) & 3]; - if (y + height <= vdc.ScanLine || y > vdc.ScanLine) + if (y + height <= vdc.ActiveLine || y > vdc.ActiveLine) continue; int patternNo = (((vdc.SpriteAttributeTable[(i * 4) + 2]) >> 1) & 0x1FF); @@ -298,11 +351,11 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx int yofs; if (vflip == false) { - yofs = (vdc.ScanLine - y) & 15; + yofs = (vdc.ActiveLine - y) & 15; if (height == 32) { patternNo &= 0x1FD; - if (vdc.ScanLine - y >= 16) + if (vdc.ActiveLine - y >= 16) { y += 16; patternNo += 2; @@ -311,17 +364,17 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx else if (height == 64) { patternNo &= 0x1F9; - if (vdc.ScanLine - y >= 48) + if (vdc.ActiveLine - y >= 48) { y += 48; patternNo += 6; } - else if (vdc.ScanLine - y >= 32) + else if (vdc.ActiveLine - y >= 32) { y += 32; patternNo += 4; } - else if (vdc.ScanLine - y >= 16) + else if (vdc.ActiveLine - y >= 16) { y += 16; patternNo += 2; @@ -330,11 +383,11 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx } else // vflip == true { - yofs = 15 - ((vdc.ScanLine - y) & 15); + yofs = 15 - ((vdc.ActiveLine - y) & 15); if (height == 32) { patternNo &= 0x1FD; - if (vdc.ScanLine - y < 16) + if (vdc.ActiveLine - y < 16) { y += 16; patternNo += 2; @@ -343,17 +396,17 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx else if (height == 64) { patternNo &= 0x1F9; - if (vdc.ScanLine - y < 16) + if (vdc.ActiveLine - y < 16) { y += 48; patternNo += 6; } - else if (vdc.ScanLine - y < 32) + else if (vdc.ActiveLine - y < 32) { y += 32; patternNo += 4; } - else if (vdc.ScanLine - y < 48) + else if (vdc.ActiveLine - y < 48) { y += 16; patternNo += 2; @@ -373,7 +426,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx byte myPriority = priority ? highPriority : lowPriority; if (PriorityBuffer[xs] < myPriority) { - FrameBuffer[(vdc.ScanLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; + FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; PriorityBuffer[xs] = myPriority; } } @@ -392,7 +445,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx byte myPriority = priority ? highPriority : lowPriority; if (PriorityBuffer[xs] < myPriority) { - FrameBuffer[(vdc.ScanLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; + FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; PriorityBuffer[xs] = myPriority; } } @@ -414,7 +467,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx byte myPriority = priority ? highPriority : lowPriority; if (PriorityBuffer[xs] < myPriority) { - FrameBuffer[(vdc.ScanLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; + FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; PriorityBuffer[xs] = myPriority; } } @@ -432,7 +485,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx byte myPriority = priority ? highPriority : lowPriority; if (PriorityBuffer[xs] < myPriority) { - FrameBuffer[(vdc.ScanLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; + FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel]; PriorityBuffer[xs] = myPriority; } } diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt index 1cfa8531e7..30c3bef723 100644 --- a/BizHawk.MultiClient/output/gamedb.txt +++ b/BizHawk.MultiClient/output/gamedb.txt @@ -2031,7 +2031,7 @@ C9D7426A Break In PCE 5C4D1991 Bullfight Ring no Haja PCE D233C05A Burning Angels PCE 47AFE6D7 Bloody Wolf PCE -BB0B3AEF Cadash PCE +BB0B3AEF Cadash PCE HBlankPeriod=83 3F9F95A4 CD-ROM System Card V1.00 (J) PCE BRAM FF2A5EC3 CD-ROM System Card V2.00 (U) PCE BRAM 283B74E0 CD-ROM System Card V2.10 (J) PCE BRAM @@ -2104,7 +2104,7 @@ BF3E2CC7 Hani in the Sky PCE 9897FA86 Hani on the Road PCE 44E7DF53 Hatris PCE EB923DE5 Heavy Unit PCE -1CAB1EE6 Hisou Kihei Serd PCE +1CAB1EE6 Hisou Kihei Serd PCE BRAM 7ACB60C8 Hit the Ice PCE B01EE703 Hono no Tataka Tamako Dodge Danpei PCE 9EC6FC6C Idol Hanafuda Fan Club PCE @@ -2165,7 +2165,7 @@ C159761B Night Creatures PCE 4D3B0BC9 Obocchama Kun PCE 8C565CB6 Ordyne PCE 5CDB3F5B Outlive PCE -E203F223 Out Run PCE +E203F223 Out Run PCE HBlankPeriod=88 B74EC562 Override PCE 7632DB90 P-47 - The Freedom Fighter PCE D6E30CCD Pac-Land PCE @@ -2227,7 +2227,7 @@ DDC3E809 Thunder Blade PCE 9107BCC8 Tiger Shark PCE CFEC1D6A Time Cruise 2 PCE 53B7784B Toilet Kids PCE -FE451C22 Tongueman's Logic PCE +FE451C22 D Tongueman's Logic PCE BRAM 72E00BC4 The Tower of Druaga PCE EB045EDF Turrican PCE 97FE5BCF TV Sports Hockey PCE