What's new

Game Boy

Shonumi

EmuTalk Member
The DX version does. You never specified exactly which one you were testing. I just assumed it was DX since most people I know didn't have the older DMG version (though one kid I knew did).

Like I said, test more games. They're probably getting errors in exactly the same area of your emulator. A wider variety of games will make it more evident.
 

fleroviux

Member
Hey :)
Yesterday I fixed a major bug in the implementation of the cpu. Instead of "ld h, d8" "ld d, d8" was executed. I somehow slipped in the opcode table. Fixing this extremely improved my emulator. Many games work better now. The Pokémon games somehow boot to the titlescreen and crash then ^^ Well the cpu_instrs test is working now, too. This means It'll be a lot easier for me to spot (and fix) bugs in my implementation.

Greetz :)
 

Rüdiger

New member
I just assumed it was DX since most people I know didn't have the older DMG version (though one kid I knew did).
I had the DMG version but played on a GBC... I faintly remember playing DX at some point but that could be my memory playing tricks on me, as I only have the old cartridge here.


Hey :)
Yesterday I fixed a major bug in the implementation of the cpu. Instead of "ld h, d8" "ld d, d8" was executed. I somehow slipped in the opcode table. Fixing this extremely improved my emulator. Many games work better now. The Pokémon games somehow boot to the titlescreen and crash then ^^ Well the cpu_instrs test is working now, too. This means It'll be a lot easier for me to spot (and fix) bugs in my implementation.

Greetz :)

Flerovium - Nice progress, I know how frustrating it is to find those pesky buggers, especially if some of them keep the tests from running. :)
Looking at the video, the opening in Zelda has the same 'jumps' in the scrolling background as on my emulator.

I finally had some time to work on my emulator.

The good news:
I found a small bug in my timer implementation and a silly mistake in the timing of conditional vs unconditional instructions.
That was enough to finally get the instr_timing test running which found some more that also seem to be in the reference I used. The test passes now.

The bad news:
None of the known issues in games (Pokemon and Zelda) showed any change.
The numbers in the IRQ demo are still off but the difference is smaller.


The mem_timing test fails for some instructions but I don't know if it is worth the trouble to fix them.
Guess I have to do some more tedious debugging to find the bugs in Pokemon and Zelda...
 

fleroviux

Member

Current Version 1.0
Pokemon and a lot of other games work :3
But there are graphics bugs. I think the problem is, that I render the whole image at once, instead of just the current line..
 

Shonumi

EmuTalk Member
Yes, rendering all the scanlines at once is a big no-no :p You have to render each scanline in succession, not at the end of a frame. The reason is that the Game Boy can change things like SX and SY (used to make the screen all wavy and for other effects). I learned this the hard way last year. Link's Awakening's intro makes extensive use of SX changing in between H-Blanks, so be sure to implement per-scanline rendering if you want to emulate the game correctly. Per-pixel rendering isn't important as far as I know. Unlike the SNES, VRAM can't be changed while the Game Boy is gathering and sending pixel data to the LCD.
 

fleroviux

Member
I just turned the switch-Statement in my CPU implementation in something like this:
opcode[0x00] = delegate() { // NOP
Pc++;
};
opcode[0x01] = delegate() { // LD BC, d16
LD_R16_D16(ref _b, ref _c);
};
opcode[0x02] = delegate() { // LD (BC), A
LD_PR16_R8(_b, _c, _a);
};
opcode[0x03] = delegate() { // INC BC
INC_R16(ref _b, ref _c);
};
opcode[0x04] = delegate() { // INC B
INC_R8(ref _b);
};
opcode[0x05] = delegate() { // DEC B
DEC_R8(ref _b);
};
opcode[0x06] = delegate() { // LD B, D8
LD_R8_D8(ref _b);
};
....
This will make it much more effecient :)
Also I began with reimplementing the video rendering, now only rendering one scanline at once..
Sadly it extremly slows down the emulator, because the scanline is rendered in the same thread that executes the cpu instructions..
I haven't found a good solution yet. Maybe I'll find a way tomorrow ^^
 

Shonumi

EmuTalk Member
I've had a busy day myself today. Earlier this week, I couldn't get Legend of Zelda: Oracle of Seasons to boot into the intro, although the Nintendo/Capcom logo would appear just fine. Turns out this requires accurate emulation of the sound registers, specifically NR52 (0xFF26). The game frequently checks the status of when a sound stops, so the emulated APU has to correctly set the lower 4 bits in NR52 for it the game to work at all. The second problem I encountered was that some of the sprites were glitchy and mis-colored. The issue was that the HDMA start and destination addresses needed to be properly masked (lower 4 bits in both are treated as 0, top 3 bits of the destination address are 0 as well). But there were still more issues; I wasn't correctly emulating double-speed mode, but after much testing I think I've got it down.

LoZ:Oracle of Seasons runs perfectly now along with many other GBC games, but Lufia: The Legend Returns (a favorite of mine) boots to a black screen. Can't wait to hunt down the bugs and fix this one :) I love digging through GB assembly.

Flerovium - I wouldn't expect much of a slowdown (at least in C++, dunno about C#) from doing CPU instructions and LCD rendering in the same thread. As soon as I execute CPU instructions, I execute LCD operations, and everything seems fine for me. Maybe you're trying to generate a scanline more frequently than you need to? I'm pretty sure you should generate the current scanline (only once though) as soon as you enter H-Blank (Mode 0) since real Game Boy hardware has already sent the relevant scanline data to the LCD by that time, meaning the scanline data is complete as far as emulation is concerned. Hope you find a good solution to your problem.

Rüdiger - What bugs do you have in Pokemon and Zelda again? Perhaps I've seen them before. I've got every Pokemon and Zelda game working, so maybe I can help ;)
 
Last edited:

fleroviux

Member
Shonumi - Drawing Bitmaps in .net seems to be quite slow. I'll have to look for a proper solution..

EDIT: I have found a solution for my problem and I've just finished recoding the background rendering :3
 
Last edited:

Shonumi

EmuTalk Member
Glad to hear that you worked something out :)

Did you manage to fix any graphical issues? Per-scanline rendering should also help a lot with Super Mario Land.
 

fleroviux

Member
Yea it fixed a lot of graphical issues! Yesterday evening I began to reimplement OBJ rendering, it seems to be a real pain to me :p
 

fleroviux

Member
FF41 - STAT - LCDC Status (R/W)
Bit 6 - LYC=LY Coincidence Interrupt (1=Enable) (Read/Write)
Bit 5 - Mode 2 OAM Interrupt (1=Enable) (Read/Write)
Bit 4 - Mode 1 V-Blank Interrupt (1=Enable) (Read/Write)
Bit 3 - Mode 0 H-Blank Interrupt (1=Enable) (Read/Write)
Bit 2 - Coincidence Flag (0:LYC<>LY, 1:LYC=LY) (Read Only)
Bit 1-0 - Mode Flag (Mode 0-3, see below) (Read Only)
0: During H-Blank
1: During V-Blank
2: During Searching OAM-RAM
3: During Transfering Data to LCD Driver

Anyone has a clue what exactly those values OAM Interrupt, V-Blank Interrupt and H-Blank Interrupt are for?
 

Rüdiger

New member
Afair, when enabled, a STAT interrupt (0x48) is triggered for each of those cases.
So when bit 6 is set, the interrupt is triggered when LYC=LY,
the same for bit 3 to 5 when the mode flag has the right value.

Some games use the LYC=LY interrupt to change register values while the screen is rendered, for example SCX to make the screen 'wobble'.
V-Blank is a bit special because it can trigger both the V-Blank and the STAT interrupt.

Shonumi: I will post something when exams are over, probably next week.
 

fleroviux

Member
Some games use the LYC=LY interrupt to change register values while the screen is rendered, for example SCX to make the screen 'wobble'.
Yes I'm aware of that. So does it mean that "OAM Interrupt", "V-blank Interrupt" etc determine, in which phases the STAT Interrupt can be triggered?
 

Shonumi

EmuTalk Member
Basically, the LCD generates an interrupt whenever it switches Modes. Take the H-Blank interrupt for example. As soon as the Game Boy's LCD enters Mode 0, you do the following:

1) Examine Bit 3 of 0xFF41.
2) If Bit 3 of 0xFF41 is set to 1, you generate a STAT interrupt (set the corresponding bit in 0xFF0F).
3) Process LCD stuff normally.

For OAM, and V-Blank, it's the same thing, except you check different bits depending on the LCD Mode. I'm fairly certain that these are only generated once the LCD switches modes, so you only perform the check once until the next mode changes (it wouldn't make sense for the hardware to constantly generate interrupts anyway).

Basically, if you're programming on the Game Boy itself, these interrupts allow you to know when the LCD changes into certain modes, as well as when the LY and LYC are equal. Obviously if you have Bits 3-6 all set, you'll be generating a lot of STAT interrupts, without knowing exactly what triggered it, so most games don't mix and match. I know Pokemon Gold/Silver/Crystal uses H-Blank interrupts a lot for battle animations.

Since I have a lot more free time, I can write you guys some test ROMs if you want to compare against hardware accuracy. While Blargg's CPU tests are great and all for getting the core of an emulator accurate, there aren't many ROMs out there for testing graphical accuracy. Although if you guys really want to stress your emulators, run a couple of GameBoy demos. Eventually I would like to write a complete test suite, so if you have any ideas or requests, let me know :)
 
Last edited:

fleroviux

Member
Hey Shonumi!
Many thanks for your explanation. As soon, as I'm back home, I'll try this out. Currently I'm simply triggering a STAT interrupt , whenever LY is increment, LY==LYC and of cause only, when IME is set and the corresponding bit in IE is set..
Also I would love to see some demo ROMs from you! This could help us extremely to make our emulators as accurate to the original as possible.
I'm using the descriptions in the Pandocs (you should know them), but the part about the STAT interrupt isn't full of details.
I would like to suggest demos for correct sprite rendering (collisions etc), scrolling, per-scanline rendering and of cause for correct VBlank / STAT Interrupt handling. For all these areas you should always test different approaches games have to do things / to put data on the display.
 

Rüdiger

New member
Here is a video of some of the remaining issues:
Pokemon Blue: some effects loop forever.
Zelda: Weird glitches when switching maps, some colors are wrong.
Oracle of Ages: Double speed is broken, some broken graphics (propably due to broken HDMA emulation).
Pokemon Crystal: broken graphics (most likely a HDMA issue) and freezes after getting a call.

It looks like most of these are caused by timing issues. The instr_timing test passes but the IRQ demo
is still a tad off. It would probably be a good idea to look at the timing between the components, which
is at the moment a bit of a mess...

Some more demos can also be found here.
 
Last edited:

Shonumi

EmuTalk Member
Hmm... I dunno about all of the problems being timing issues. I have never been able to pass the instr_timing test, even though I'm 99% certain I'm doing it right :p Last time I checked, I failed that test, but all of the above games work just fine. About each game in particular...

Pokemon Blue - May be related to STAT interrupts. I would imagine that one type of interrupt (likely H-Blank) is being triggered so the game can safely modify SCX for the scanline for the wave-like effects. Seems like all the GB Pokemon games (Red through Crystal) don't make the very first scanline move when attacks make those wave-like effects (LY=LYC test maybe? Perhaps the effect just couldn't be done when testing for LY=0). If it loops forever rather than crashing, it's usually a sign that you're not feeding it input it expects (an interrupt, a certain value in the MMIO registers, stuff like that). The best thing to do is look at the GB assembly in a debugger and compare it in an emulator. Time consuming, but effective, since eventually your emulator will diverge from a correct, working emulator and you can then pinpoint where exactly.

Zelda - No crashes, so it's most likely an MMU issue or LCD issue. Looks like the Tile Map is getting messed up, but obviously the game logic still knows where things like the houses would be (since Link still bumps into the house, even though it's glitched). As for the stuttering in the intro, that definitely looks like a timing issue, or at least you might not be accounting for SCX properly before drawing a scanline. As I said earlier, the intro changes SCX a lot. But I would find that strange since Pokemon uses the same SCX trick and your emulator ran that just fine. Double-check it to be sure though.

Oracle of Ages - Yeah, the Oracle games need a lot of attention to HDMAs (it doesn't use General HDMA, from what I know, just HDMAs during H-Blank). This link is really helpful, and actually explains more about HDMAs than Nintendo did themselves: http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_VRAM_DMA_Transfers_.28CGB_only.29

As for double-speed, I kinda struggled to implement it correctly too, in fact, I only knew my implementation was broken because the Oracle games were messed up. I solved it by simply halving the CPU cycles the LCD acknowledged after each instruction (my emulated APU is not cycle-based, not yet), but by sending the original amount of CPU cycles to the timers. The CPU runs at 2x its normal operating speed (meaning all timers run twice as fast too) but LCD operations, DMA transfers run at the same speed. The setup I just described follows that, but it took me a while to figure it out.

Pokemon Crystal - Yeah, most likely an HDMA issue. Until I fixed my implementation of the HDMA, I had graphical issues like that in Crystal. This game makes extensive use of H-Blank HDMAs (it may occasionally use a General HDMA, but I don't specifically remember seeing that called). Probably not the source of your issue, but always make sure to use the correct VRAM bank when reading/writing. That was a source of frustration for me, briefly though.

Other stuff - Sprite palettes in DMG games are off. You may know how to fix it already, but just make sure you're correctly reading OBP0 and OBP1. Also, seems like you still have BG/Sprite priority issues (Suicune in the intro of Crystal should be behind the grass). For reference, there are only 4 cases where a sprite's pixel will prevail over the BG's pixel (GBC only):

1: BG Priority is 0 - Sprite Priority is 0 - Sprite Color is 1-3
2: BG Priority is 0 - BG Color is 0 - Sprite Priority is 1 - Sprite Color is 1-3
3: BG Priority is 1 - BG Color is 0 - Sprite Color is 1-3 (Sprite priority doesn't matter here)
4: Bit 0 of LCDC (0xFF40) is 0 - Sprite Color is 1-3

Hope this helps. I'm still working on one test ROM at the moment. The DMG bootrom, unfortunately, leaves some uncleared entries in Tile Map 0. Not too much to worry about, but it is more effort on my part to clean it up. I'll probably post at least two test online this weekend if you guys want to try them out for yourselves (and yes, they will be verified against real hardware, one already is).
 
Last edited:

Top