What's new

Game Boy

Rüdiger

New member
I came to the conclusion of it being "switchable memory banks". (Feel free to correct me.) How would I implement this?

Yes, while the region from 0x0000 to 0x3FFF always maps to the first 16KiB, the region from 0x4000 to 0x7FFF can be switched to any ROM bank depending on the MBC (memory bank controller) in the game cartridge.
There are different ways to implement this. I use a lookup table with 16 entries so that each entry maps 4KiB of memory, using the highmost 4 bits of the address. That size also fits nicely for the switchable RAM banks in the GBC and some other special regions.
This of course means that you can no longer access the whole memory as a single array.

Related to your second question, you might also want to treat memory access to 0xFF00-0xFFFF (and maybe some other regions) differently than regular memory, as some of them will trigger special behaviour.
For example, writing to 0xFF0F might trigger an interrupt after the current instruction, or writing to the ROM banks accesses the MBC.
Your console output looks fine, at least if you call it only after a write to 0xFF01.


And a (not so) small update from me: I reimplemented the CPU core in arm assembly, this time avoiding some of the bottlenecks of my old implementation, mainly interrupts and timer handling. Instruction decode/dispatch should also be faster.
The CPU passes almost all tests, with the only failures due to missing timers. Next up are the callbacks for special registers (timers, interrupts...) and graphics. It looks like I can't reuse too much of my old code, either due to the different structure of the emulator or because it is too slow. For the graphics, I'm considering caching the tiles to speed up the rendering, as the tile accesses seem to take a considerable amount of time.
It will probably take some weeks before I can work on it again, but I plan to have it running on the arm board at usable speed in the next few months.

In other news, it looks like one of my favorite gameboy emulators goomba color is under development again.
 

Shonumi

EmuTalk Member
There are three bytes in the cartridge header that determine all you need to know. They'll tell you the MBC type, how much ROM there is, and how much (if any) external RAM is present. -> http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type

You'll need to look at the bytes at 0x147, 0x148, and 0x149. It may seem a bit confusing, but handling MBCs is much more sane than trying to handle all of the various NES cartridge types ;) Info on how each MBC works can be found here -> http://gbdev.gg8.se/wiki/articles/Memory_Bank_Controllers

There are a few MBC types not listed in the link provided, only because they were exotic (MBC6 for multi-carts? and MBC7 for Kirby Tilt 'n' Tumble) and technically came out after Pan Docs was initially released. VBA-M's source code is probably the 'best' (and I use that word loosely, there are hardly any comments in the code!) documentation of the MBC7. MESS supports MBC6, but if you're looking at its code, just be aware that it's not technically FOSS. Those games are edge cases though; if you just want to run 99% of commercial games, MBC1, MBC2, MBC3, and MBC5 are what you should focus on.
 

CyanPrime

New member
Hi, I have a quick question. I'm making a GameBoy emulator, and I'm using this tutorial as my main one: http://imrannazar.com/GameBoy-Emulation-in-JavaScript:-Memory

In this part of the tutorial it's saying to create five arrays:
BIOS
ROM
WRAM
ERAM
and ZRAM

So my question is: What size should each of these arrays be? I know the tutorial says to use dynamic ones (for now, maybe?) but I'd rather set their size so I can go:
Code:
var bios = new ArrayBuffer(0x00FF); 
this.bios = new Uint8Array(bios);

to cast the array as a Uint8 array.
 

Shonumi

EmuTalk Member
Eventually, you really should go dynamic. The following memory areas are rather elastic (mostly due to banking):

* Boot ROM (aka BIOS) - Can be 0x100 bytes for DMG or 0x900 bytes for the GBC
* ROM - Can vary depending on MBC type and specified size in ROM header
* WRAM - Can vary between the DMG and GBC (GBC has a few banks for this)
* ERAM - Can vary depending on MBC type and specified size in ROM header
* VRAM - Can vary between the DMG and GBC (GBC has 2x the VRAM with 2 banks)

But if you're just trying to get 32KB DMG games like Tetris to work (i.e. no ROM banking, no External RAM) the sizes listed on that page are exactly the sizes you'll need:

* Boot ROM -> 0x100 bytes
* ROM Bank 0 and 1 -> 0x4000 bytes each
* VRAM -> 0x2000 bytes
* ERAM -> 0x2000 bytes
* WRAM -> 0x2000 bytes (it's mirrored, however, so the shadow area occupies another 0x1E00 bytes)
* ZRAM -> 0x80 bytes
 

mendus

New member
Hi all,

Whats the best method to debug the cpu? I just finished writing it and has at least a few bugs so if I run roms I get no graphics. I think the rasterizer is ok, since if I load a memory dump done with another emulator, it renders it alright.

Any ideas? I tried to follow a ROM instruction by instruction to see the outcome, but this was really tiring.
 

Shonumi

EmuTalk Member
I can't stress enough how good it is to build a good debugger into your emulator. That saved me tons of time when I worked on the GBA, and I wish I had done it when working on the GB/GBC. CPU bugs are not fun since they can be incredibly hard to pinpoint.

What I would do is start working on a debugger. Even if it's something simple, like just printing out text via the CLI, you should do it. Being able to run the emulated CPU instruction by instruction is a must, as are breakpoints. Once you've got that set up, compare your debugger's output with the output of a known, working debugger (BGB is great for this). If you find a point where your debug logs differ from another debugger, that's going to be a point of interest. I know going through the entire game one instruction at a time is tiring, and in fact you shouldn't be doing that. Instead, consider these techniques I use to determine where the problem lies.

* Choose a breakpoint you know your emulated CPU will hit frequently. Be careful not to choose something that gets called thousands of times per second. Watching when the code jumps to the VBLANK interrupt is a great place to start. There are only roughly 60 VBLANKs per second on the GB, so that's frequent enough to see where you go wrong without checking it thousands of time just to see when it goes wrong. With any luck, you'll be able to say "Hey, after the 5th VBLANK, something happens, my registers are different from BGB's!" and go from there.

* Run your emulator for a bit (a couple of seconds while the problem occurs), then check the last few instructions that were running before closing your emulator. Is your emulator running valid code? That is to say, do other emulators run that same instruction at that specific PC? You can verify this by setting a breakpoint in BGB. If BGB never hits that breakpoint, but your emulator is executing code at that PC, that's a very good indication that something is going wrong on your end.

* Run your emulator for a bit (like before), then examine the code. Is it stuck in a loop? It may be trying to grab a value from a register that you're not emulating. If it expects a certain value, but you keep feeding it 0x0 or 0xFF, that can easily cause problems.

* Once you find a point where your emulator diverges from a working emulator like BGB, work your way backwards. to try and find the root cause. This takes practice and patience, depending on what's going on and what you have and haven't emulated correctly. I like to keep a log of my thoughts for a specific game and take notes on what I think might be the problem. Again, this is from my time working on GBA emulation, but you can see some of my thought process here:

Debugging Lunar Legend
Debugging Super Mario Advance - Mario Bros. Classic mode
Debugging Mega Man Zero

Ignore the ARM/THUMB assembly, but that's what I do when I start debugging. I start asking questions and writing down clues until I find the answer. Hope this helps you out ;)
 

mendus

New member
[MENTION=110864]Shonumi[/MENTION] Thank you for the advice. I already wrote a simple debugger that draws the register to screen after each instruction, together with the places in memory pointed by PC and its immediates. However, going step by step was a little bit tiring, because almost all instructions are correct and I needed to go quite far to find an error. Ill try to log these into a file so I can compare easier with those of a working emulator. Does BGB allow loggin the instructions into a file? I did not manage to do it.
 

Shonumi

EmuTalk Member
I don't know if BGB can log output to a file, but it shouldn't be hard to hack that functionality into another emulator's source code (like VBA-M).

Debugging things instruction by instruction is not the way to go, unless you know where to look for the problem. You first need to locate where you problem is, approximately. Breakpoints are the single greatest debugging tool/time saver in my opinion. If your debugger doesn't have them, implement it.

If you really have no idea what's going on, I can't recommend the VBLANK breakpoint method enough. Set a breakpoint for the VBLANK interrupt vector and eventually after a certain number of VBLANKs, you should see your emulator doing something others don't.

What game are you trying to play, and where is it having problems (intro? start screen? some other random time?). If you have source code available, I could take a look as well.
 

mendus

New member
I tried running tetris and the blargs cput test rom. They both meet a bug before anything is loaded into VRAM. I have barely gone through debugging though. I dont know what the breakpoints are, I'll google it now.
 

Shonumi

EmuTalk Member
You'll probably have googled it by now, but just in case you haven't, breakpoints are essentially points in the code where you tell your program to stop once certain conditions are true. This allows you to halt the program and examine its current state. The most common forms of breakpoints for emulator debugging are ones that involve the PC. That is to say, whenever you set a PC breakpoint, the emulator will run normally until the PC = whatever value you want. This is very helpful since it allows you to potentially skip hundreds of instructions that are of no interest to you. With breakpoints, you wouldn't have to run your emulator instruction by instruction to reach every VBLANK, for example. Just tell it to stop whenever the PC == 0x40 and print the registers/other info you want, while ignoring the thousands of other instructions that happened in between. The point of this is to find out when you are getting weird results and then trace it backwards to the source. It's very much a game of hide and seek, really. Some bugs are pesky and obscure ;)

Good luck by the way.
 

mendus

New member
Ok, so I checked and it seems all roms have a jump instruction in PC = 0x40 and it seems its updating data from the registers 0xFF** and probably vRAM (there are many subrutine calls). I assume that whenever a vertical blank happens (i.e. every 17556 cycles approximately) a CALL 0x40 instruction will happen. This would be approximately 6000 instructions at an average of ~3 cycles/instruction. Hence, if I set a breakpoint there, I would need to debug this many instructions when I find mismatching register values.

Are my assumptions correct? If so, isn't there another way to go forward by, say only 500 instructions? It's easy to implement in my emulator, but it seems that BGB only stops at breakpoints defined by the PC. And I don't know if there is another address that happens more or less this often as an instruction.

- - - Updated - - -

Also, what is a good way to stop the dispatch loop? I am using scanf() but this makes the render and debug windows difficult to move and sometimes windows complains that the program is not answering. Is there any other simple way?
 

Shonumi

EmuTalk Member
Here's what I would do. First, find out how many VBLANKs it takes for the issue to appear (if it happens after the first couple or VBLANKs that's great). You only need to check the VBLANK breakpoint and look at the registers. Once you have narrowed it down, i.e. the problem occurs between VBLANKs 5 and 6 for example, it's time to do some digging.

Ask yourself what it is you should be looking at. VRAM is a good target in your case. When does the game write to VRAM? Your black screen issue sounds like you're not writing to VRAM when you should, or you're writing incorrect values. BGB can break whenever it writes to memory areas you define; just go to Debug -> access breakpoints (format is xxxx-yyyy for the range, leave the value blank to catch any write). See where BGB hits this code and what happens in your emulator, then work your way back.

About stopping your emulator, I always used C++'s std::cin (for console input). It always halts the program until it receives input. Dunno if that's comparable to scanf() as I don't use a lot of C.
 
Last edited:

RossIain

New member
Hdma/gdma

Working on adding Color support to my emulator, it current works great in "Non Color Mode" with DMG roms, and with DMG roms in "Color Mode".
However after implementing HDMA and GDMA transfers some of the Color roms that rely heavily on them don't really render correctly.

Pokemon Crystal, Yellow, and Mario Deluxe all work correctly after implementing the HDMA/GDMA transfers.
mhoDopY.png
A8XiVKj.png
NdGpcfM.png


Shantae renders correctly every 2nd frame, but I seem to be getting "garbage" every other frame:
3SJ0Fz7.png
tkFl2W1.png


Zelda Oracle of Seasons/Ages seems to mostly be correct in gameplay but in the opening scenes I get a lot of incorrectly rendered graphics. This one is from Oracle of Seasons:
Y6B2EXN.png


Donkey Kong Country seems to flicker as well like Shantae, although both graphics I get are still not entirely incorrect, here's one of them:
4lPa53z.png


I'm almost entirely sure these are caused by errors in my HDMA/GDMA implementations, but I can't seem to pinpoint whereabouts I'm going wrong.
 
Last edited:

RossIain

New member
Managed to fix my problem, turned out my code to extract a value from vram in color mode would always select from bank 1 and not bank 0.
The games I was having problems with are looking a lot better now :)

T9woqnq.png
RXwxIjz.png
kx8wfP5.png


The opening screens in Aladdin, and the bottom of the screen during gameplay are still quite a bit messed up but I've realised my double speed implementation
is not quite correct when deciding to increment the timers, so i'm going to attempt to fix that before looking at any further graphical errors.

79K32qX.png
9htJTqu.png
 

RossIain

New member
I've implemented double speed by halving the cycles passed to the sound and lcd which essentially makes the cpu and timers run twice as fast.

This has fixed a lot of graphical errors in games which use double speed. Rayman now manages to boot and play correctly.
2dJi3sD.png


However still having the same problem with Aladdin as well as multiple other games which give me the same distorted background effect.

Aladdin:
zLZ7Cfc.png
GJ3bCiz.png
wSKScjh.png
K2efe3Y.png


Tomb Raider Curse Of The Sword:
knsO91G.png
lCtYLCl.png


The New Addams Family Series:
YU3Yn0B.png
iGEgYX4.png


I'm having a hard time trying to figure out what's exactly causing this effect.
 

Shonumi

EmuTalk Member
Fwiw, I get the exact same results in my emulator (pixel for pixel). It's probably some behavior present in GDMA or HDMA that I overlooked. Honestly have not touched GBC emulation in over a year, but I'm picking up things again. Planning on integrating my previous GB/GBC code into my GBA emulator.

EDIT: Doesn't look to be a DMA issue. Possibly something to do with mid-screen color palette changes? Hmm...
 
Last edited:

Shonumi

EmuTalk Member
[MENTION=111375]RossIain[/MENTION] - It definitely look like something to do with midscanline color changes. Some games did this to utilize more colors per frame, creating bitmap-like effects. I think it would have been way too complicated to do this for animation, generally, so it makes sense that mostly still images are affected. You could probably take a screenshot in BGB or VBAM and count the number of unique colors and see that it's greater than 64 (assuming they only used BG palettes).
 

RossIain

New member
[MENTION=111375]RossIain[/MENTION] - It definitely look like something to do with midscanline color changes. Some games did this to utilize more colors per frame, creating bitmap-like effects. I think it would have been way too complicated to do this for animation, generally, so it makes sense that mostly still images are affected. You could probably take a screenshot in BGB or VBAM and count the number of unique colors and see that it's greater than 64 (assuming they only used BG palettes).

I really hoped it wasn't a midscanline palette change as I really don't want to start implementing that, also the Aladdin intro with the blue screen doesn't use many colors at all which seems
a tad overkill to use this method. Yesterday I was using the BGB VRAM viewer to look at the palettes and tiles. Turns out the palettes were the same as mine at the end of the frame but were definitely
being updated during the frame. The attributes of my tiles also matched the attributes of the tiles in the BGB viewer. So I think the problem is that the palettes aren't being updated
correctly,

The part of my emulator which I was least confident that worked entirely correctly was my lcd driver, since I originally built it from a tutorial which wasn't that accurate
and had been updating bits and pieces to it as I went along. I spent most of today rewriting it from scratch looking into source code from other emulators I know that can display
these graphics and looking up as much documentation as I could find. There was definitely some parts I was missing, especially to do with generating LCDC interrupts.

I think possibly an LCDC status interrupt is meant to be generated in the case of these particular background images to update the palettes?

The rewrite of my lcd code has managed to fix this particular problem :)

Tw2qiGu.png
dgXbFrq.png
ONDMxmU.png
dZk7thG.png
 

Top