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 ======= ======= TurboGrafx compatibility issues =======
General: General:
+ Noise Channel isn't right. Less obnoxious now, still not happy. + Don't have a complete list of instructions affected by T flag. Currently warns if SET precedes an unrecognized instruction.
+ 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.
+ Audio volumes are probably wrong. + Audio volumes are probably wrong.
+ LFO is not implemented, though I can't tell. + LFO is not implemented, though I can't tell.
+ Screen is too tall on several games. Obv resolution calculation is not 100% correct. + 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 extends too many lines - like 3 extra or so
Aero Blaster - Bottom of Screen possibly extends too many lines Air Zonk - Fully playable, doesn't freeze, but some gfx/timing issues
Agmeda - Very minor timing/gfx glitches esp at bottom of screen Alice - Screen too tall; glitches when scrolling up, but in pcejin also,
Air Zonk - Freezes shortly into a new game
Alice - Screen possibly too tall; glitches when scrolling up, but in pcejin also,
but not ootake; ergo probably a timing artifact but not ootake; ergo probably a timing artifact
Andre Panza Kickbx- Doesn't boot. Looks like semi pedigree as Battle Royal. Andre Panza Kickbx- Doesn't boot. Looks like semi pedigree as Battle Royal.
Battle Ace - Some gfx glitches
Battle Royale - Doesnt boot 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 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 Cross Wiber - Minor; Raster on wrong line
Cyber Dodge - Minor gfx issues Davis Cup Tennis - Some timing issue, splash screen is too slow
Davis Cup Tennis - Doesnt boot at all right now
Dead Moon - Screen is too tall Dead Moon - Screen is too tall
Dragon Egg - Doesn't boot at all
Dungeon Explorer - Freeze in 'intro' - gfx corruption in-game Dungeon Explorer - Freeze in 'intro' - gfx corruption in-game
Fighting Run - Corruption issues Fighting Run - Corruption issues
Final Blaster - Does crazy shit with video modes; freezes if intro is not skipped Final Blaster - Intro does crazy shit with video modes; not sure what if anything to do about it
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
Griffon - Screen goes black because game changes video mode mid-frame Griffon - Screen goes black because game changes video mode mid-frame
Gunboat - Crash / CPU Break (Needs BRAM) Gunboat - Crash / CPU Break (Needs BRAM)
Hisou Kihei Serd - Doesn't boot Jack Nicholas Golf- Some screens are too tall and reveal bad gfx below the intended visible screen
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
Legend of Hero Ton- Slight gfx- check top of screen Legend of Hero Ton- Slight gfx- check top of screen
Lode Runner - Freezes in new game Lode Runner - Freezes in new game
Madoo Granzort - Graphics issues because VPC renderer is not using new frame 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 - timing Metal Stoker - Tearing when scrolling vertically at bottom of screen - screen too tall?
MML Demo - Echo channels are too loud (equal volume!) 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 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 *** Populous - Game freezes on starting new game - *** NEEDS BATTERY SAVERAM ***
Power Drift - Timing glitch... starting new game runs slower than it should Power Drift - Timing glitch... starting new game runs slower than it should
Power Tennis - Freezes in (elaborate) intro screen. decent target though Power Tennis - Elaborate intro screen doesnt display right
R-Type - Funky corruption after killing final boss in Stage 8
Raiden - Sprites and BG get out of sync with current timing 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 Side Arms - Screen is like 4 pixels too tall
Sinistron - Raster effect errors Sinistron - Much less bad raster effect errors now
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
Tiger Road - On second level, sprites should be getting masked from the top status area somehow 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: Stuff I Fixed That's Not In Other Docs:

View File

@ -39,14 +39,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
// 21,477,270 Machine clocks / sec // 21,477,270 Machine clocks / sec
// 7,159,090 Cpu cycles / 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) public PCEngine(NecSystemType type)
{ {
Type = type; Type = type;
@ -108,7 +100,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public void FrameAdvance(bool render) public void FrameAdvance(bool render)
{ {
Controller.UpdateControls(Frame++); Controller.UpdateControls(Frame++);
//Log.Note("CPU","======== FRAME {0} =========",Frame);
PSG.BeginFrame(Cpu.TotalExecutedCycles); PSG.BeginFrame(Cpu.TotalExecutedCycles);
if (SuperGrafx) 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 + BackgroundY is the current offset into the scroll plane. It is set with BYR
register at certain sync points and incremented every scanline. register at certain sync points and incremented every scanline.
Its values range from 0 - $1FF. 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 ScanLine;
public int BackgroundY; public int BackgroundY;
@ -27,7 +23,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
private byte[] InterSpritePriorityBuffer = new byte[512]; private byte[] InterSpritePriorityBuffer = new byte[512];
private int latchedDisplayStartLine; private int latchedDisplayStartLine;
private int ActiveLine; private int ActiveLine;
private int RCRCount;
public void ExecFrame(bool render) public void ExecFrame(bool render)
{ {
@ -35,10 +30,16 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
ActiveLine = 0 - latchedDisplayStartLine; ActiveLine = 0 - latchedDisplayStartLine;
ScanLine = 0; ScanLine = 0;
int HDS = (Registers[HSR] >> 8) & 0x7F; int hds = (Registers[HSR] >> 8) & 0x7F;
int HDE = (Registers[HDR] >> 8) & 0x7F; int hde = (Registers[HDR] >> 8) & 0x7F;
int hblankCycles = (HDS + HDE + 2) * 8; int vds = Registers[VPR] >> 8;
//hblankCycles -= 2; 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) switch (vce.DotClock)
{ {
@ -47,7 +48,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
case 2: hblankCycles = (hblankCycles*2)/3; break; 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); //Log.Note("VDC","ScanLine {0} (ActiveLine {1}, RCR {2}, BGY {3})",ScanLine, ActiveLine, RCRCount, BackgroundY);
bool InActiveDisplay = false; bool InActiveDisplay = false;
@ -55,35 +56,33 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
InActiveDisplay = true; InActiveDisplay = true;
if (ActiveLine == 0) if (ActiveLine == 0)
{
BackgroundY = Registers[BYR]; 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; StatusByte |= StatusRasterCompare;
cpu.IRQ1Assert = true; cpu.IRQ1Assert = true;
} }
} }
if (ActiveLine == BufferHeight && IntVerticalBlank)
{
StatusByte |= StatusVerticalBlanking;
cpu.IRQ1Assert = true;
}
cpu.Execute(hblankCycles); cpu.Execute(hblankCycles);
if (InActiveDisplay && render) if (InActiveDisplay && render)
RenderScanLine(); RenderScanLine();
if (ScanLine == VBlankScanline && VBlankInterruptEnabled)
{
Log.Note("VDC", "Firing VBlank interrupt at {0}", ScanLine);
StatusByte |= StatusVerticalBlanking;
cpu.IRQ1Assert = true;
}
cpu.Execute(455-hblankCycles); cpu.Execute(455-hblankCycles);
if (ScanLine == FrameHeight - 1) if (ScanLine == VBlankScanline)
UpdateSpriteAttributeTable(); UpdateSpriteAttributeTable();
if (InActiveDisplay == false && DmaRequested) if (InActiveDisplay == false && DmaRequested)
@ -91,7 +90,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
ScanLine++; ScanLine++;
ActiveLine++; ActiveLine++;
RCRCount++;
BackgroundY++; BackgroundY++;
BackgroundY &= 0x01FF; BackgroundY &= 0x01FF;
} }
@ -115,7 +113,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if ((Registers[DCR] & 1) > 0) if ((Registers[DCR] & 1) > 0)
{ {
Console.WriteLine("FIRING SATB DMA COMPLETION IRQ"); Log.Note("VDC","FIRING SATB DMA COMPLETION IRQ");
StatusByte |= StatusVramSatDmaComplete; StatusByte |= StatusVramSatDmaComplete;
cpu.IRQ1Assert = true; cpu.IRQ1Assert = true;
} }

View File

@ -37,10 +37,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public bool BackgroundEnabled { get { return (Registers[CR] & 0x80) != 0; } } public bool BackgroundEnabled { get { return (Registers[CR] & 0x80) != 0; } }
public bool SpritesEnabled { get { return (Registers[CR] & 0x40) != 0; } } public bool SpritesEnabled { get { return (Registers[CR] & 0x40) != 0; } }
public bool IntVerticalBlank { get { return (Registers[CR] & 0x08) != 0; } } public bool VBlankInterruptEnabled { get { return (Registers[CR] & 0x08) != 0; } }
public bool IntRasterCompare { get { return (Registers[CR] & 0x04) != 0; } } public bool RasterCompareInterruptEnabled { get { return (Registers[CR] & 0x04) != 0; } }
public bool IntSpriteOverflow { get { return (Registers[CR] & 0x02) != 0; } } public bool SpriteOverflowInterruptEnabled { get { return (Registers[CR] & 0x02) != 0; } }
public bool IntSpriteCollision { get { return (Registers[CR] & 0x01) != 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 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; } } 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 StatusSpriteOverflow = 0x02;
public const byte StatusSprite0Collision = 0x01; public const byte StatusSprite0Collision = 0x01;
private const int VramSize = 0x8000;
private HuC6280 cpu; private HuC6280 cpu;
private VCE vce; private VCE vce;
@ -88,6 +90,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
{ {
this.cpu = cpu; this.cpu = cpu;
this.vce = vce; this.vce = vce;
Registers[HSR] = 0x00FF;
Registers[HDR] = 0x00FF;
Registers[VPR] = 0xFFFF;
Registers[VCR] = 0xFFFF;
ReadBuffer = 0xFFFF;
} }
public void WriteVDC(int port, byte value) public void WriteVDC(int port, byte value)
@ -108,37 +116,32 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
{ {
Registers[RegisterLatch] &= 0x00FF; Registers[RegisterLatch] &= 0x00FF;
Registers[RegisterLatch] |= (ushort) (value << 8); 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 case MARR: // Memory Address Read Register
ReadBuffer = VRAM[Registers[MARR] & 0x7FFF]; ReadBuffer = VRAM[Registers[MARR] & 0x7FFF];
break; break;
case VWR: // VRAM Write Register 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)); UpdatePatternData((ushort) (Registers[MAWR] & 0x7FFF));
UpdateSpriteData((ushort) (Registers[MAWR] & 0x7FFF)); UpdateSpriteData((ushort) (Registers[MAWR] & 0x7FFF));
} }
Registers[MAWR] += IncrementWidth; Registers[MAWR] += IncrementWidth;
break; break;
case CR:
//if (Registers[CR] == 0)
//Log.Note("CPU", "****************** WRITE TO CR: {0:X}", Registers[CR]);
break;
case BXR: case BXR:
Registers[BXR] &= 0x3FF; Registers[BXR] &= 0x3FF;
break; break;
case BYR: case BYR:
Registers[BYR] &= 0x1FF; Registers[BYR] &= 0x1FF;
BackgroundY = Registers[BYR]; BackgroundY = Registers[BYR];
//Console.WriteLine("Updating BYR to {0} at scanline {1}", BackgroundY, ScanLine);
break; break;
case HDR: // Horizontal Display Register - update framebuffer size case HDR: // Horizontal Display Register - update framebuffer size
FrameWidth = RequestedFrameWidth; FrameWidth = RequestedFrameWidth;
@ -190,7 +193,7 @@ break;
case 1: // unused case 1: // unused
return 0; return 0;
case 2: // LSB case 2: // LSB
return (byte) (ReadBuffer & 0xFF); return (byte) ReadBuffer;
case 3: // MSB case 3: // MSB
retval = (byte)(ReadBuffer >> 8); retval = (byte)(ReadBuffer >> 8);
if (RegisterLatch == VRR) if (RegisterLatch == VRR)
@ -221,7 +224,7 @@ break;
if ((Registers[DCR] & 2) > 0) if ((Registers[DCR] & 2) > 0)
{ {
Console.WriteLine("FIRE VRAM-VRAM DMA COMPLETE IRQ"); Log.Note("Vdc","FIRE VRAM-VRAM DMA COMPLETE IRQ");
StatusByte |= StatusVramVramDmaComplete; StatusByte |= StatusVramVramDmaComplete;
cpu.IRQ1Assert = true; cpu.IRQ1Assert = true;
} }
@ -315,6 +318,9 @@ break;
UpdatePatternData(i); UpdatePatternData(i);
UpdateSpriteData(i); UpdateSpriteData(i);
} }
CompleteMSBWrite(HDR);
CompleteMSBWrite(VDW);
} }
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
@ -345,6 +351,9 @@ break;
RegisterLatch = reader.ReadByte(); RegisterLatch = reader.ReadByte();
ReadBuffer = reader.ReadUInt16(); ReadBuffer = reader.ReadUInt16();
StatusByte = reader.ReadByte(); 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 ((ScanLine + 64) == (VDC1.Registers[6] & 0x3FF))
{ {
if (VDC1.IntRasterCompare) if (VDC1.RasterCompareInterruptEnabled)
{ {
VDC1.StatusByte |= VDC.StatusRasterCompare; VDC1.StatusByte |= VDC.StatusRasterCompare;
CPU.IRQ1Assert = true; CPU.IRQ1Assert = true;
@ -161,20 +161,20 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if ((ScanLine + 64) == (VDC2.Registers[6] & 0x3FF)) if ((ScanLine + 64) == (VDC2.Registers[6] & 0x3FF))
{ {
if (VDC2.IntRasterCompare) if (VDC2.RasterCompareInterruptEnabled)
{ {
VDC2.StatusByte |= VDC.StatusRasterCompare; VDC2.StatusByte |= VDC.StatusRasterCompare;
CPU.IRQ1Assert = true; CPU.IRQ1Assert = true;
} }
} }
if (ScanLine == 240 && VDC1.IntVerticalBlank) if (ScanLine == 240 && VDC1.VBlankInterruptEnabled)
{ {
VDC1.StatusByte |= VDC.StatusVerticalBlanking; VDC1.StatusByte |= VDC.StatusVerticalBlanking;
CPU.IRQ1Assert = true; CPU.IRQ1Assert = true;
} }
if (ScanLine == 240 && VDC2.IntVerticalBlank) if (ScanLine == 240 && VDC2.VBlankInterruptEnabled)
{ {
VDC2.StatusByte |= VDC.StatusVerticalBlanking; VDC2.StatusByte |= VDC.StatusVerticalBlanking;
CPU.IRQ1Assert = true; CPU.IRQ1Assert = true;
@ -295,7 +295,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if (width == 32) if (width == 32)
patternNo &= 0x1FE; patternNo &= 0x1FE;
int yofs = 0; int yofs;
if (vflip == false) if (vflip == false)
{ {
yofs = (vdc.ScanLine - y) & 15; yofs = (vdc.ScanLine - y) & 15;