ekeeke / Genesis-Plus-GX

An enhanced port of Genesis Plus - accurate & portable Sega 8/16 bit emulator
Other
697 stars 198 forks source link

Rick Dangerous 2 title screen graphical glitch #555

Closed Danniel79 closed 5 months ago

Danniel79 commented 5 months ago

Rick Dangerous 2 (W) (REV1 1) (Unl) Tested on Pal Wii.Genesis Plus GX last commit. Rick Dangerous 2 (W) (REV1.1) (Unl) CRC32:4366ADD7 MD5:511D9C63DDFE13695C82647798DF2078 Black stripe on the right Fusion 364 doesn't have this problem. Rick Dangerous 2 (W) (REV1 1) (Unl)000

ekeeke commented 5 months ago

It appears to be a regression introduced when adding emulation of 68k bus refresh delays (in https://github.com/ekeeke/Genesis-Plus-GX/commit/47761b9b8fd35eabd7b3ff3dc5ab0f54f1d95133) as it was fine before that commit so it's probably related to some timing sensitive code in that unlicensed game that worked more or less by chance before that.

Testing on Analogue Mega-SG and in Blastem shows similar glitch, although less visible as it appears lower on the screen, but I can confirm it is not visible at all on real hardware. I will try to investigate what causes it (looks like bg plane initialization being interrupted too early and not finished properly) but I am sure it also occurs on real hardware, however just later enough that it is not visible (either in the black bar above the license notice or into the bottom border).

Danniel79 commented 5 months ago

Very interesting. Thanks for the answer.

ekeeke commented 5 months ago

Note that it does not occur when emulating PAL Mega Drive

image

vs in 60Hz mode

image

And I confirm this is caused by game code not being interrupt-safe: screen initialization routine (composed of several sequences of VRAM writes) is getting interrupted by VINT handler which itself writes to VRAM and VSRAM, leaving VDP address and code in another state when returning from VINT to interrupted VRAM write sequence, thus causing some VRAM addresses not being correctly initialized as they should

[224(224)][555(555)] VRAM 0xe524 write -> 0x305 (7634)  => VRAM write sequence is interrupted by VINT
[224(0)][821(821)] m68k IRQ Level = 6(0x300) (762c)
[224(224)][821(821)] INT Level 6 ack (762c)
---> VINT cleared
[224(0)][821(821)] m68k IRQ Level = 0(0x600) (762c)
[224][1192] m68k run to 3420 cycles (46a), irq mask = 600 (0)
[225][3446] m68k run to 6840 cycles (53ba), irq mask = 600 (0)
[226][6855] m68k run to 10260 cycles (d1ca), irq mask = 600 (0)
[226(226)][9431(2591)] VRAM 0xd802 write -> 0x0 (8232)
[227][10369] m68k run to 13680 cycles (819e), irq mask = 600 (0)
[227(227)][10901(641)] VSRAM 0x2 write -> 0x0 (81c2)  => VINT handler changes VDP access code/address to VSRAM
[228][13687] m68k run to 17100 cycles (5488), irq mask = 600 (0)
[229][17145] m68k run to 20520 cycles (5560), irq mask = 600 (0)
[230][20603] m68k run to 23940 cycles (5614), irq mask = 600 (0)
[230(230)][21261(741)] VSRAM 0x4 write -> 0x306 (7634)  => VRAM write sequence continues but with incorrect VDP access code/address
[230(230)][21569(1049)] VSRAM 0x6 write -> 0x307 (7634)
[230(230)][21863(1343)] VSRAM 0x8 write -> 0x308 (7634)
[230(230)][22157(1637)] VSRAM 0xa write -> 0x309 (7634)
[230(230)][22465(1945)] VSRAM 0xc write -> 0x30a (7634)
[230(230)][22759(2239)] VSRAM 0xe write -> 0x30b (7634)
[230(230)][23053(2533)] VSRAM 0x10 write -> 0x30c (7634)
[230(230)][23361(2841)] VSRAM 0x12 write -> 0x30d (7634)
[230(230)][23655(3135)] VSRAM 0x14 write -> 0x30e (7634)
[231][23949] m68k run to 27360 cycles (762e), irq mask = 300 (0)
[231(231)][23949(9)] VSRAM 0x16 write -> 0x2e1 (7634)
[231(231)][24257(317)] VSRAM 0x18 write -> 0x30f (7634)
[231(231)][24551(611)] VSRAM 0x1a write -> 0xa97 (7634)
[231(231)][24845(905)] VSRAM 0x1c write -> 0xa85 (7634)        => VRAM write sequence ends
[231(231)][26385(2445)] VRAM 0xe580 write -> 0x285 (7634)    => another VRAM write sequence starts, with new VRAM address
[231(231)][26679(2739)] VRAM 0xe582 write -> 0x297 (7634)
[231(231)][26987(3047)] VRAM 0xe584 write -> 0x2ae (7634)

The VSRAM writes to 0x4-0x1 should instead be VRAM writes to 0xe526-0x53e: these VRAM addresses correspond to plane A tile map so the end result is that the screen is missing some tiles.

On real hardware, most likely, VINT either occurs between two VRAM write sequences or interrupts a VRAM write sequence that initialize portions of the screen where there is a black area anyway. In any cases, it mostly works "by luck".

Danniel79 commented 5 months ago

Excellent investigation.

ekeeke commented 5 months ago

Fixed by https://github.com/ekeeke/Genesis-Plus-GX/commit/f9f16d7a552c5606caea52c2179ca2831b8e0177

The solution was to add emulation of 68k delays when Z80 access to 68k bus.