• entries
177
531
• views
163829

# Synchronization hell

376 views

I've squished a few more bugs and have almost all the games working now. Most still have some graphical problems, likely due to timing. There are also two games I continue to have trouble with, Mortal Kombat which refuses to pass the "presented by Midway" screen and Super Mario Land 2, which won't go past the title screen. Yes I know it was working last entry, but it's a finicky bastard.

The first bug and the one that has been causing all the games to flicker, was that I wasn't copying enough bytes for the sprite DMA. Part of the problem here is the documentation:

Quote:
 FF46 Name - DMA Contents - DMA Transfer and Start Address (W) The DMA Transfer (40*28 bit) from internal ROM or RAM ($0000-$F19F) to the OAM (address $FE00-$FE9F) can be performed. It takes 160 microseconds for the transfer. 40*28 bit = #140 or #$8C. As you can see, it only transfers$8C bytes of data. OAM data is $A0 bytes long, from$0-$9F. But if you examine the OAM data you see that 4 bits are not in use. 40*32 bit = #$A0, but since 4 bits for each OAM is not used it's 40*28 bit. It transfers all the OAM data to OAM RAM. The DMA transfer start address can be designated every $100 from address$0000-$F100. That means$0000, $0100,$0200, \$0300....

Got all that? Well basically each sprite is 4 bytes, but you only need the first 28 bits. When I first read this I though it just copied the first 0x8C bytes. Maybe the hardware does only transfer 28 bits per sprite for speed, but I can get away with just transferring 0xA0 bytes. Why they couldn't just say 0xA0, I have no idea.

Next bug was some fixing the interrupt timing. See the GameBoy has an instruction called HALT which justs halts the processor until an interrupt occurs. I've been ignoring it since most games just check the LCD registers after and if nothing happened jump back to the HALT. However there are some games that don't and seem to be built around it. Damn programming was a lot harder back then, I swear these guys where counting clock cycles.

Finally a bug that caused some of the games to flicker their title screens. Problem was that I was only checking if the LCD was enabled when I did the actual rendering of the whole screen during VBlank. Some games though would turn the screen on right when the VBlank occurred so now I check it every scan line.

I don't know why I wrote all that, so here's what you're really here for:

Kirby's Dreamland 2 and Gargoyle's Quest, I haven't tested them throughly, but at least they start.

The cycle counting in some games was absolutely insane. Battletoads on the NES is one of the worst - in a really ironic twist, very inaccurate emulators run Battletoads just fine. But on the near-accurate emulators, it has a tendency to lock up on level 2 if the timing of the "sprite 0 hit" flag relative to the VBlank interrupt isn't within about a CPU cycle. Battletoads was my nightmare on the NES, as well as a nightmare for almost every other NES emulator author that I know.

I imagine there are equivalent games on the GB, and they're probably going to make you want to pull your hair out.

That's interesting that there's a halt instruction on the GB, the NES has no such (not exactly, there are some opcodes that halt the CPU, but they're more of a bug in the CPU than an official instruction - and they halt it for GOOD. You have to power cycle to get it to do anything after that). I wonder how different NES game programming would be if there were a halt instruction like on the Gameboy?

With a Z80 you could do di \ halt, but then there's always the fixed NMI to get around that, if the hardware has something firing NMIs (the TI-83 series calculators don't).

One big advantage of halt is that it puts the CPU in a low power mode, especially handy for battery-powered devices.

I'm curious how you're handling the screen being switched on and off; in my case I check the display each scanline and if it's off I just fill in the blanking colour, if not I render as usual. I assume this is what you're doing now by checking each scanline? I assume scanline-based timing is sufficiently accurate for the NES/GameBoy?

On the SMS VDP, VRAM access needs to be much slower during the active display, so switching it off prematurely would be one way of getting more performance out of it (at the cost of reducing the resolution). One game in particular (Earthworm Jim) is a right bastard for VDP shenanegins, switching it off mid-way, fiddling with sprite flags, then switching it back on again.

Quote:
 Original post by Drilian I wonder how different NES game programming would be if there were a halt instruction like on the Gameboy?

Probably not a whole lot different, the games are still interrupt driven and require very accurate timing. The HALT is mainly there to save battery power and chew up cycles between interrupts.

Quote:
 Original post by benryves I'm curious how you're handling the screen being switched on and off; in my case I check the display each scanline and if it's off I just fill in the blanking colour, if not I render as usual. I assume this is what you're doing now by checking each scanline? I assume scanline-based timing is sufficiently accurate for the NES/GameBoy?

Yeah, if the display or background is disabled I just fill that scanline with color 0 of the background palette. There's an interrupt for when the scanline is equal to some memory register, which is fun because they constantly change it several times per frame.

Quote:
 Original post by benryves On the SMS VDP, VRAM access needs to be much slower during the active display, so switching it off prematurely would be one way of getting more performance out of it (at the cost of reducing the resolution).

I haven't bothered changing the various LCD state times depending on if it's enabled or not, most games only disable it when they load maps so it shouldn't really matter. However one document does say that the amount of sprites on the line does affect how long the HBlank is, so I probably need to implement that.