Tennis
Missing STAT interrupt
The window layer in the PPU is mostly used for menus, or overlays. It can be offset on the X- and the Y-Axis, but only to positive numbers. This is what caused this bug in Tennis for me. The scoreboard in the upper right corner is the window layer, that is offset to the right of the screen. But since we can’t offset it “up”, it shows the scoreboard and blocks the actual court with white color.

To fix this, I had to implement / fix the STAT interrupt. The STAT-interrupt can be caused on the LYC=LY coincidence. This way, a programmer can set LYC to the line he wants the window layer to stop drawing. The interrupt will fire once the current line drawn (LY) is equal to LYC, and we can just disable window drawing completely (until the next frame). With this implementation, we can achieve the result we hoped for.

Not handling panning on sound channels
Since I did not plan on implementing the panning of sound channels, I completely ignored the registers responsible for panning. A mistake that cause me multiple days of frustration and debugging, until I finally discovered the relevance of these registers. Tennis makes use of the panning registers, to disable channels. This is a very weird technology, as there is e.g. the length counter that is designed to do something like that. Without handling these panning registers though, some sounds won’t stop, or won’t stop sweeping, like you can hear on the ball bounce.
Note: In the following video the sound bug on the ball bounce is already greatly reduced by other factors. Sadly I don't have any video left of the initially longer sound problem, where the sound wouldn't stop until another sound appeared on the channel.
Also, the racket swing sounds too long, and off, also caused by the same behavior.
After implementing a check for the panning registers, if there is any sound at all for the channel, before pushing to the channels buffer, all sound bugs were fixed.
// enabled channel
if (SC4enabled && ((readFromMem(0xff26) >> 3) & 1) && (readFromMem(0xff21) & 0xf8) && (readFromMem(0xff25) & 0x88)) {
// push data to buffer
SC4buf.push_back((SC4lfsr & 0x1) ? 0 : (float) SC4amp / 100);
SC4buf.push_back((SC4lfsr & 0x1) ? 0 : (float) SC4amp / 100);
...
Super Mario Land
This game was a good baseline for me, since it has scrolling, complex sprites etc. I fixed minor scrolling bugs (due to wrapping on the VRAM), sprite flipping and timings later on. But what boggled my mind was this problem. If you are familiar with the automatic demos on this game, you will see that the demo end way too early.

After a lot of debugging and testing, my mistake was pretty clear. My V-Blank interrupt was firing on every cycle inside V-Blank, so way too often! After I fixed this, to only fire once V-Blank entered, the demos ran the normal length.
// if vblank, draw once (drawFlag)
if (!frameDrawnFlag && readFromMem(0xff44) == 144) {
// V-Blank interrupt IF
writeToMem(0xff0f, readFromMem(0xff0f) | 1);
drawFrame();
frameDrawnFlag = 1;
}
Mario & Yoshi / Super Mario Land 2
These two games gave me headaches again. After other games started to run perfectly smooth and normal, Mario & Yoshi did not boot at all, and only showed a blank screen, while Super Mario Land 2 – 6 Golden Coins would show the title screen, but when pressed START would only fade out, to return back to the title screen (instead of the save game selection screen)

I finally got this fixed, after I let the PPU only fire V-Blank interrupts if the Display is not off. So, I modified the code from above slightly.
// if vblank, draw once (drawFlag)
if (!frameDrawnFlag && readFromMem(0xff44) == 144) {
// only draw if display is enabled
if (readFromMem(0xff40) >> 7) {
// V-Blank interrupt IF
writeToMem(0xff0f, readFromMem(0xff0f) | 1);
drawFrame();
frameDrawnFlag = 1;
}
}
With this minimal fix, I was able to get past Super Mario Land 2’s title screen, and also boot into Mario & Yoshi.


Despite the missing sprite ordering (as you can see as Mario goes down the pipe in the SM2 gif), these were all the bugs I encountered for now. So it was time, to add some features to the emulator, to make it neat.
Comments