PCE: Significant VDC timing improvements

This commit is contained in:
beirich 2011-03-13 03:20:28 +00:00
parent e5cb8ec071
commit 50a06e38cd
5 changed files with 68 additions and 100 deletions

View File

@ -1,71 +1,41 @@
======= TurboGrafx compatibility issues =======
General:
+ Noise Channel isn't right. Less obnoxious now, still not happy.
+ T Flag implemented for ADC, EOR. Log warning if used by any other instructions.
Should probably just do it for the others, but I hate not having a test case.
+ Video timing is off.
+ Don't have a complete list of instructions affected by T flag. Currently warns if SET precedes an unrecognized instruction.
+ Audio volumes are probably wrong.
+ LFO is not implemented, though I can't tell.
+ Screen is too tall on several games. Obv resolution calculation is not 100% correct.
Adventure Island - Flicker on title screen sequence - timing?
Aero Blaster - Bottom of Screen possibly extends too many lines
Agmeda - Very minor timing/gfx glitches esp at bottom of screen
Air Zonk - Freezes shortly into a new game
Alice - Screen possibly too tall; glitches when scrolling up, but in pcejin also,
Aero Blaster - Bottom of Screen extends too many lines - like 3 extra or so
Air Zonk - Fully playable, doesn't freeze, but some gfx/timing issues
Alice - Screen too tall; glitches when scrolling up, but in pcejin also,
but not ootake; ergo probably a timing artifact
Andre Panza Kickbx- Doesn't boot. Looks like semi pedigree as Battle Royal.
Battle Ace - Some gfx glitches
Battle Royale - Doesnt boot
Boxy Boy - Freezes when starting game; seems to remain broken even after rewinding (!!)
Bravoman - Is currently booting. But has been boot-problematic in the past.
Cadash - Camera is all crazy. Very sensitive to interrupt timing and timing in general.
Chase HQ - Press start -"O" sprite gets left on screen. probably timing on SATB DMA
Chouzetsu Rinjin - Japanese version of Bravoman. Currently working.
College Pro Basebl- In startup sequence, sprites are crazy, game goes nuts when starting game
Cross Wiber - Minor; Raster on wrong line
Cyber Dodge - Minor gfx issues
Davis Cup Tennis - Doesnt boot at all right now
Davis Cup Tennis - Some timing issue, splash screen is too slow
Dead Moon - Screen is too tall
Dragon Egg - Doesn't boot at all
Dungeon Explorer - Freeze in 'intro' - gfx corruption in-game
Fighting Run - Corruption issues
Final Blaster - Does crazy shit with video modes; freezes if intro is not skipped
Final Solider - Graphics corruption issues - some right at the beginning that might be a good target
Ghost Mannor - Game will freeze in some circumstances mid gameplay
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
Gunboat - Crash / CPU Break (Needs BRAM)
Hisou Kihei Serd - Doesn't boot
Idol Hanafuda Fan Club - Doesn't boot
Impossamole - Gfx issues
Jack Nicholas Golf- Doesnt boot basically
Legendary Axe - BYR updated on the wrong line of the screen, but playable.
Legendary Axe II - Fairly serious corruption issues, but playable now
Jack Nicholas Golf- Some screens are too tall and reveal bad gfx below the intended visible screen
Legend of Hero Ton- Slight gfx- check top of screen
Lode Runner - Freezes in new game
Madoo Granzort - Graphics issues because VPC renderer is not using new frame timing
Metal Stoker - Tearing when scrolling vertically at bottom of screen - timing
Madoo Granzort - Graphics issues because SGX VPC renderer is not using new frame timing
Metal Stoker - Tearing when scrolling vertically at bottom of screen - screen too tall?
MML Demo - Echo channels are too loud (equal volume!)
Naxat Open - Crashes when you start new game
NHK Taiga Drama Ta- Sprite flicker and corruption issues
Night Creatures - Some gfx glitches
Outrun - Raster issues, music slows when paused
Paranoia - MAYBE game freeze in like 5th level? not sure, didnt verify.
Paranoia - Game hits BREAK on 3rd level. need to investigate
Populous - Game freezes on starting new game - *** NEEDS BATTERY SAVERAM ***
Power Drift - Timing glitch... starting new game runs slower than it should
Power Tennis - Freezes in (elaborate) intro screen. decent target though
R-Type - Funky corruption after killing final boss in Stage 8
Power Tennis - Elaborate intro screen doesnt display right
Raiden - Sprites and BG get out of sync with current timing
Rastan Saga 2 - Doesn't boot - lots of invalid reads?
Sekikehara - Gfx corruption, some palette problems?
Side Arms - Screen is like 4 pixels too tall
Sinistron - Raster effect errors
Soldier Blade - Freezes about 5 minutes in. Always in the same spot, fortunately. I have a savestate.
Soukoban World - J version of Boxy Boy - Same bugs
Thunder Blade - After beating the 1st 3d area, game semi-freezes
Sinistron - Much less bad raster effect errors now
Tiger Road - On second level, sprites should be getting masked from the top status area somehow
Valkyrie No Densetsu - Boots now, but with pretty severe issues
Stuff I Fixed That's Not In Other Docs:

View File

@ -38,14 +38,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
// PC Engine timings:
// 21,477,270 Machine clocks / sec
// 7,159,090 Cpu cycles / sec
// At 60.00 FPS
// 357,954 mclks / frame
// 119,318 Cpu cycles / frame
// 263 lines / frame:
// 1361 mclks / line
// 454 Cpu cycles / line
public PCEngine(NecSystemType type)
{
@ -108,7 +100,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public void FrameAdvance(bool render)
{
Controller.UpdateControls(Frame++);
//Log.Note("CPU","======== FRAME {0} =========",Frame);
PSG.BeginFrame(Cpu.TotalExecutedCycles);
if (SuperGrafx)

View File

@ -15,10 +15,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
+ BackgroundY is the current offset into the scroll plane. It is set with BYR
register at certain sync points and incremented every scanline.
Its values range from 0 - $1FF.
+ RCRCount is the current offset into the RCR register. It is reset to $40
on the first active display line, and incremented every line. Its effective
range is $40 - $146.
*/
public int ScanLine;
public int BackgroundY;
@ -27,7 +23,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
private byte[] InterSpritePriorityBuffer = new byte[512];
private int latchedDisplayStartLine;
private int ActiveLine;
private int RCRCount;
public void ExecFrame(bool render)
{
@ -35,10 +30,16 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
ActiveLine = 0 - latchedDisplayStartLine;
ScanLine = 0;
int HDS = (Registers[HSR] >> 8) & 0x7F;
int HDE = (Registers[HDR] >> 8) & 0x7F;
int hblankCycles = (HDS + HDE + 2) * 8;
//hblankCycles -= 2;
int hds = (Registers[HSR] >> 8) & 0x7F;
int hde = (Registers[HDR] >> 8) & 0x7F;
int vds = Registers[VPR] >> 8;
int vsw = Registers[VPR] & 0x1F;
int VBlankScanline = vds + vsw + Registers[VDW] + 1;
if (VBlankScanline > 261)
VBlankScanline = 261;
int hblankCycles = (hds + hde + 2) * 8;
switch (vce.DotClock)
{
@ -47,7 +48,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
case 2: hblankCycles = (hblankCycles*2)/3; break;
}
for (; ScanLine < 262;)
for (; ScanLine < 263;)
{
//Log.Note("VDC","ScanLine {0} (ActiveLine {1}, RCR {2}, BGY {3})",ScanLine, ActiveLine, RCRCount, BackgroundY);
bool InActiveDisplay = false;
@ -55,35 +56,33 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
InActiveDisplay = true;
if (ActiveLine == 0)
{
BackgroundY = Registers[BYR];
RCRCount = 0x40;
//Console.WriteLine("Latched BYR {0} at scanline {1}",BackgroundY, ScanLine);
}
if ((RCRCount) == (Registers[RCR] & 0x3FF))
if (ActiveLine == (Registers[RCR] & 0x3FF) - 0x40)
{
if (IntRasterCompare)
if (RasterCompareInterruptEnabled)
{
//Log.Note("VDC", "Enter RCR interrupt at scanline {0}",ScanLine);
Log.Note("VDC", "Firing RCR interrupt at {0}", ScanLine);
StatusByte |= StatusRasterCompare;
cpu.IRQ1Assert = true;
}
}
if (ActiveLine == BufferHeight && IntVerticalBlank)
{
StatusByte |= StatusVerticalBlanking;
cpu.IRQ1Assert = true;
}
cpu.Execute(hblankCycles);
if (InActiveDisplay && render)
RenderScanLine();
if (ScanLine == VBlankScanline && VBlankInterruptEnabled)
{
Log.Note("VDC", "Firing VBlank interrupt at {0}", ScanLine);
StatusByte |= StatusVerticalBlanking;
cpu.IRQ1Assert = true;
}
cpu.Execute(455-hblankCycles);
if (ScanLine == FrameHeight - 1)
if (ScanLine == VBlankScanline)
UpdateSpriteAttributeTable();
if (InActiveDisplay == false && DmaRequested)
@ -91,7 +90,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
ScanLine++;
ActiveLine++;
RCRCount++;
BackgroundY++;
BackgroundY &= 0x01FF;
}
@ -115,7 +113,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if ((Registers[DCR] & 1) > 0)
{
Console.WriteLine("FIRING SATB DMA COMPLETION IRQ");
Log.Note("VDC","FIRING SATB DMA COMPLETION IRQ");
StatusByte |= StatusVramSatDmaComplete;
cpu.IRQ1Assert = true;
}

View File

@ -35,12 +35,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
}
}
public bool BackgroundEnabled { get { return (Registers[CR] & 0x80) != 0; } }
public bool SpritesEnabled { get { return (Registers[CR] & 0x40) != 0; } }
public bool IntVerticalBlank { get { return (Registers[CR] & 0x08) != 0; } }
public bool IntRasterCompare { get { return (Registers[CR] & 0x04) != 0; } }
public bool IntSpriteOverflow { get { return (Registers[CR] & 0x02) != 0; } }
public bool IntSpriteCollision { get { return (Registers[CR] & 0x01) != 0; } }
public bool BackgroundEnabled { get { return (Registers[CR] & 0x80) != 0; } }
public bool SpritesEnabled { get { return (Registers[CR] & 0x40) != 0; } }
public bool VBlankInterruptEnabled { get { return (Registers[CR] & 0x08) != 0; } }
public bool RasterCompareInterruptEnabled { get { return (Registers[CR] & 0x04) != 0; } }
public bool SpriteOverflowInterruptEnabled { get { return (Registers[CR] & 0x02) != 0; } }
public bool SpriteCollisionInterruptEnabled { get { return (Registers[CR] & 0x01) != 0; } }
public int BatWidth { get { switch((Registers[MWR] >> 4) & 3) { case 0: return 32; case 1: return 64; default: return 128; } } }
public int BatHeight { get { return ((Registers[MWR] & 0x40) == 0) ? 32 : 64; } }
@ -81,6 +81,8 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public const byte StatusSpriteOverflow = 0x02;
public const byte StatusSprite0Collision = 0x01;
private const int VramSize = 0x8000;
private HuC6280 cpu;
private VCE vce;
@ -88,6 +90,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
{
this.cpu = cpu;
this.vce = vce;
Registers[HSR] = 0x00FF;
Registers[HDR] = 0x00FF;
Registers[VPR] = 0xFFFF;
Registers[VCR] = 0xFFFF;
ReadBuffer = 0xFFFF;
}
public void WriteVDC(int port, byte value)
@ -108,37 +116,32 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
{
Registers[RegisterLatch] &= 0x00FF;
Registers[RegisterLatch] |= (ushort) (value << 8);
CompleteMSBWrite();
CompleteMSBWrite(RegisterLatch);
}
}
private void CompleteMSBWrite()
private void CompleteMSBWrite(int register)
{
switch (RegisterLatch)
switch (register)
{
case MARR: // Memory Address Read Register
ReadBuffer = VRAM[Registers[MARR] & 0x7FFF];
break;
case VWR: // VRAM Write Register
if (Registers[MAWR] < 0x8000)
if (Registers[MAWR] < VramSize) // Several games attempt to write past the end of VRAM
{
VRAM[Registers[MAWR] & 0x7FFF] = Registers[VWR];
VRAM[Registers[MAWR]] = Registers[VWR];
UpdatePatternData((ushort) (Registers[MAWR] & 0x7FFF));
UpdateSpriteData((ushort) (Registers[MAWR] & 0x7FFF));
}
Registers[MAWR] += IncrementWidth;
break;
case CR:
//if (Registers[CR] == 0)
//Log.Note("CPU", "****************** WRITE TO CR: {0:X}", Registers[CR]);
break;
case BXR:
Registers[BXR] &= 0x3FF;
break;
case BYR:
Registers[BYR] &= 0x1FF;
BackgroundY = Registers[BYR];
//Console.WriteLine("Updating BYR to {0} at scanline {1}", BackgroundY, ScanLine);
break;
case HDR: // Horizontal Display Register - update framebuffer size
FrameWidth = RequestedFrameWidth;
@ -190,7 +193,7 @@ break;
case 1: // unused
return 0;
case 2: // LSB
return (byte) (ReadBuffer & 0xFF);
return (byte) ReadBuffer;
case 3: // MSB
retval = (byte)(ReadBuffer >> 8);
if (RegisterLatch == VRR)
@ -221,7 +224,7 @@ break;
if ((Registers[DCR] & 2) > 0)
{
Console.WriteLine("FIRE VRAM-VRAM DMA COMPLETE IRQ");
Log.Note("Vdc","FIRE VRAM-VRAM DMA COMPLETE IRQ");
StatusByte |= StatusVramVramDmaComplete;
cpu.IRQ1Assert = true;
}
@ -315,6 +318,9 @@ break;
UpdatePatternData(i);
UpdateSpriteData(i);
}
CompleteMSBWrite(HDR);
CompleteMSBWrite(VDW);
}
public void SaveStateBinary(BinaryWriter writer)
@ -345,6 +351,9 @@ break;
RegisterLatch = reader.ReadByte();
ReadBuffer = reader.ReadUInt16();
StatusByte = reader.ReadByte();
CompleteMSBWrite(HDR);
CompleteMSBWrite(VDW);
}
}
}

View File

@ -152,7 +152,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if ((ScanLine + 64) == (VDC1.Registers[6] & 0x3FF))
{
if (VDC1.IntRasterCompare)
if (VDC1.RasterCompareInterruptEnabled)
{
VDC1.StatusByte |= VDC.StatusRasterCompare;
CPU.IRQ1Assert = true;
@ -161,20 +161,20 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if ((ScanLine + 64) == (VDC2.Registers[6] & 0x3FF))
{
if (VDC2.IntRasterCompare)
if (VDC2.RasterCompareInterruptEnabled)
{
VDC2.StatusByte |= VDC.StatusRasterCompare;
CPU.IRQ1Assert = true;
}
}
if (ScanLine == 240 && VDC1.IntVerticalBlank)
if (ScanLine == 240 && VDC1.VBlankInterruptEnabled)
{
VDC1.StatusByte |= VDC.StatusVerticalBlanking;
CPU.IRQ1Assert = true;
}
if (ScanLine == 240 && VDC2.IntVerticalBlank)
if (ScanLine == 240 && VDC2.VBlankInterruptEnabled)
{
VDC2.StatusByte |= VDC.StatusVerticalBlanking;
CPU.IRQ1Assert = true;
@ -295,7 +295,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if (width == 32)
patternNo &= 0x1FE;
int yofs = 0;
int yofs;
if (vflip == false)
{
yofs = (vdc.ScanLine - y) & 15;