What's new

Game Boy

icepir8

Moderator
The code looks correct.

Hey icepir8

I may be missing something, but I think aprentice's code is still not doing right. Just look at this case, being all flags clear and A=0x0A. According to the table you posted, "numer added to byte" should be 0x06, but for aprentice's code,

Code:
void op0x27() //DAA 
{ 
   if(regF&0x40) //Negative Flag Set 
   { 
      if((regA&0x0F)>0x09 || regF&0x20) 
     { 
        regA-=0x06; //Half borrow: (0-1) = (0xF-0x6) = 9 
        if((regA&0xF0)==0xF0) regF|=0x10; else regF&=~0x10; 
     } 

     if((regA&0xF0)>0x90 || regF&0x10) regA-=0x60; 
   } 
   else 
   { 
       if((regA&0x0F)>9 || regF&0x20) // regA&0x0F == 0x0A so this is true
       { 
           regA+=0x06; //Half carry: (9+1) = (0xA+0x6) = 10 // regA == 0x10 now
           if((regA&0xF0)==0) regF|=0x10; else regF&=~0x10; // regA & 0xF0 == 0x10 now so false and carry flag is cleared.
        } 

        if((regA&0xF0)>0x90 || regF&0x10) regA+=0x60; // both conditions false so do not add 0x60 to regA.
    } 

    if(regA==0) regF|=0x80; else regF&=~0x80; 
}

it turns to be 0x66. The problem I see on his code is that flags are being updated while results are still being computed. As far as I understand the opcode, flags should be updated after the amount to be added/substracted has been dedided.

Just wanted to know what you think about that.

By the way, I've got absolutely nothing against aprentice :p I'm just testing his code cause it seems several of you are using it in your emus.

Thanks again.

S.

I hope that makes sense to you. If this is not happening then look for a type in the code you are compiling.

btw I think there may be a problem with clearing the carry flag during the opperation.
 

srastol

New member
If this is not happening then look for a type in the code you are compiling.

Uhm, you're right, got a typo in aprentice's code when copying it into my workspace. That's my fault. But now I've got a new question regarding input value 0x9A. If you don't mind, let me expose my point to the details, and see if we can find where the problem is. Let's have A register hold value 0x9A (regA = 0x9A), all flags being clear (regF = 0x00). According to the table "Detailed info DAA" (post #1072), our case is the 5th listed,

Code:
--------------------------------------------------------------------------------
|           | C Flag  | HEX value in | H Flag | HEX value in | Number  | C flag|
| Operation | Before  | upper digit  | Before | lower digit  | added   | After |
|           | DAA     | (bit 7-4)    | DAA    | (bit 3-0)    | to byte | DAA   |
|------------------------------------------------------------------------------|
|           |    0    |     0-9      |   0    |     0-9      |   00    |   0   |
|   ADD     |    0    |     0-8      |   0    |     A-F      |   06    |   0   |
|           |    0    |     0-9      |   1    |     0-3      |   06    |   0   |
|   ADC     |    0    |     A-F      |   0    |     0-9      |   60    |   1   |
|           |    0    |     9-F      |   0    |     A-F      |   66    |   1   | <-- our case

Let's put some numbers to aprentice's code,

Code:
00: void op0x27() //DAA 
01: { 
02:    if(regF&0x40) //Negative Flag Set 
03:    { 
04:       if((regA&0x0F)>0x09 || regF&0x20) 
05:      { 
06:         regA-=0x06; //Half borrow: (0-1) = (0xF-0x6) = 9 
07:         if((regA&0xF0)==0xF0) regF|=0x10; else regF&=~0x10; 
08:      } 
09: 
10:      if((regA&0xF0)>0x90 || regF&0x10) regA-=0x60; 
11:    } 
12:    else 
13:    { 
14:        if((regA&0x0F)>9 || regF&0x20) 
15:        { 
16:            regA+=0x06; //Half carry: (9+1) = (0xA+0x6) = 10 
17:            if((regA&0xF0)==0) regF|=0x10; else regF&=~0x10; 
18:         } 
19: 
20:         if((regA&0xF0)>0x90 || regF&0x10) regA+=0x60; 
21:     } 
22:
23:     if(regA==0) regF|=0x80; else regF&=~0x80; 
24: }

Now, the logic, as I see it, flows like this:

1.- Line 02 condition is not satisfied, our number is positive. Jump to line 14.
2.- "(regA&0x0F)>9" is satisfied. Move to 16.
3.- 0x06 is added to regA, regA turns into 0xA0. Move to 17.
4.- Condition is not satisfied, carry C flag is cleared, regF keeps being 0x00. Move to line 20.
5.- Condition holds, 0x60 is added to regA, regA turns into 0x00 (0x100 actually). Move to line 23.
6.- Condition holds, zero Z flag is set, regF turns into 0x80. End of function.

See the problem? At the end we've added 0x66 to regA, that's correct, but at step 5 carry C flag has not been set on regA's overflow. Back to the table, our case is expected to set C flag. So again, I may be too tired to spot where my fault is (it's been a long day), or actually a bug in the code.

I just hope me not being too much a pain for you, heh..

S.
 
Last edited:

icepir8

Moderator
I made a few changes to the code I believe this is correct now.

Code:
#defing CarryMask 0x10
#define HalfCarryMask 0x20
#define NegFlagMask 0x40

00: void op0x27() //DAA 
01: { 
02:    if(regF & NegFlagMask) //Negative Flag Set 
03:    { 
04:       if((regA & 0x0F)>0x09 || regF & HalfCarryMask) 
05:      { 
06:         regA-=0x06; //Half borrow: (0-1) = (0xF-0x6) = 9 
07:         if((regA & 0xF0) == 0xF0) regF |= CarryMask; 
              // We don't clear the carry/barrow flag in the DAA
              //else regF &= ~CarryMask; 
08:      } 
09: 
10:      if((regA & 0xF0) > 0x90 || regF & CarryMask) 
              {
                   regA-=0x60; 
                   regF |= CarryMask;
               }
11:    } 
12:    else 
13:    { 
14:        if((regA & 0x0F)>9 || regF & HalfCarryMask) 
15:        { 
16:            regA += 0x06; //Half carry: (9+1) = (0xA+0x6) = 10 
17:            // never happens in BCD math 
                //if((regA & 0xF0)==0) regF |= CarryMask; 
                // We don't clear the carry/barrow flag in the DAA
                 //else regF &= ~CarryMask; 
18:         } 
19: 
20:         if((regA&0xF0)>0x90 || regF & 0x10) 
                   {
                        regA+=0x60;
                        regF |= CarryMask;
                   }
21:     } 
22:
23:     if(regA==0) regF|=0x80; else regF&=~0x80; 
24: }
 

fenixagua

New member
Hi, guys!

I am developing an emulator for Game Boy, but I have no information on the HuC1, HuC3, MBC4, MBC5, MBC7, among others, and the pan doc not have and did not think so.

Could you help me?
 

Exophase

Emulator Developer
You must be pretty far along to be interested in such things.

Here's an MBC5 document: http://www.ziegler.desaign.de/cgbmbc5.pdf
HuC1 is allegedly MBC1 with infrared support. Unless you plan on emulating that you shouldn't have to do anything special for it.

I can't find information on the other mappers, so you probably want to look at source of emulators like Gambatte to get an idea. I imagine that they have core functionality that's similar or identical to one of the other mappers. MBC4 might just be an MBC5 that doesn't support double speed mode.
 

fenixagua

New member
You must be pretty far along to be interested in such things.
Oh, yes, almost all the opcodes listed in GB Cribsheet are made and I have done the basics with the timers and special registers (LY, etc.). And runs games smoothly MBC1.
Here's an MBC5 document: http://www.ziegler.desaign.de/cgbmbc5.pdf
HuC1 is allegedly MBC1 with infrared support. Unless you plan on emulating that you shouldn't have to do anything special for it.

Thank you for this information!



Know how it is done to activate the infrared HuC1?
 

Exophase

Emulator Developer
Hey fenixagua, congratulations on making what must be a pretty complete GB emulator by now. How is sound working? A lot of people doing GB emulators seem to have difficulty with sound, at least relative to everything else.

I wish I could tell you more about the obscure mappers, but unfortunately the best I could do would be to personally dig through what open source emulators there are and try to glean that info. I'll leave that task to you, since I probably wouldn't be able to find anything better.
 

MicBeaudoin

New member
Hello,

I'm making a GB emulator right now, but there is something that bugs me. Knowing that the GB cpu runs at 4 Mhz, shouldn't it run 4 millions cycles per second?

In the docs, it's said that 4096 cycles should be run each second(not sure about this):

4. FF04 (DIV)
Name - DIV
Contents - Divider Register (R/W)
This register is incremented 16384(16384/4=4096)
(~16779 on SGB) times a second. Writing
any value sets it to $00.

The DIV register is the cycle count right? So let's say I run the NOP opcode, the DIV reg should be +=4?

I'll give you screenshots when it'll be working, I just need to make a GUI using Qt and the code of the rendering part and it should work(for cartridges without MBC of course)

Thanks
 

MicBeaudoin

New member
Nevermind, I just read the whole topic and my questions were already answered. I'll send screenshots here when it's showing some pixels.
 

MicBeaudoin

New member
Hello,

Here are some screenshots of my emu running some demos(scroller and "test")


http://bayimg.com/iaJLaaaCk
http://bayimg.com/hajlnAaCk


Unfortunately, Tetris is not working because I'm stuck into an infinite loop:

opcode_0x20()
opcode_0xF0()
opcode_0xFE()

It looks like it's looking for a particular state of the LY register, even though it is incremented as stated in the docs.
All I get is a blank screen with a small black line.
http://bayimg.com/iaJlFAAcK
 

CHR15x94

Local nut
Hey there. Sure is quiet around here...

Well, I started my GameBoy emulator a few months ago, and worked on it for a bit, then took a break from it for a while. About a week ago I started working on it again and have ironed out some bugs. Unfortunately, I still have quite a few issues to sort out.

My emulator is done in SDL, and made in the Code::Blocks (10.05) IDE, compiled using MinGW.

Here's a few screenshots of my emulator running a few ROMs (commercial and PD).

**SNIP**

Also, thanks to CodeSlinger. I'm currently using his tile drawing code and it seems to work quite well. :satisfied My drawing code never worked 100%, so I used his to help my emulator progress a bit faster. Once I've debugged my emulator some more, I'll write my own drawing routines.

Thanks, and any suggestions, questions or whatever are welcome. :D


EDIT: Worked on my emulator's MBC1 and MBC3 code, as well as fixed JoyPad emulation. Tetris worked after fixing JoyPad code (goes to menu and in game, no graphics errors other than no sprites (not implemented)). Super Mario Land works 100%, (again, other than no sprites), Super Mario Land 2 goes to menu and file/save select screen but crashes when the save is loaded. Pokemon Red/Blue display distorted graphics for the Pokemon sprites/tiles (on the title screen, etc) and crashes upon going in game and crashes if you don't mash the buttons at the cutscene at the start. On the other hand, Pokemon Silver/Gold seem to play 100% (haven't tested everything yet though). Kirby's Dream Land plays alright other than Kirby falls through the floor (I assume anyways, can't see Kirby, no sprites). Boxxle also seems to work fine, other than the odd graphics error or two. Link's Awakening also seems to work OK, but I think the ROM crashes upon leaving the first house. Altered Space hangs at the copyright screen, Prehistorik Man displays garbage which is messed around by some SCX/SCY effect, then crashes.

Anyways, I'm going to finish up what's left of MBC1 and MBC3, as well as add MBC2 support, and add a rough implementation of sprites, then I'll release the source of my emulator, as well as a build of it (Windows only).


EDIT 2: Here it is. My emulator and it's source code, all in one ZIP file. And yes, I know my emulator isn't that great. I probably won't be working on it for too much longer either (hopefully). This release includes some changes:

  • Fixed some bugs in rotate instructions (fixes graphics errors in Pokemon Red/Blue, and allows it to go ingame, fixes a bug that stops the user from choosing a starter Pokemon in Pokemon Silver, fixes some graphics errors in Wave Race, fixes collisions in Kirby's Dreamland)
  • Added basic sprite support. (Basic drawing, X/Y axis flipping. No priorities, etc.)
  • Finished MBC1 and MBC2 support. MBC3 support is OK as well, but no RTC emulation is present.

And still TODO...:
  • Finish sprite emulation
  • Emulate other MBCs.
  • Emulate STOP, HALT and DAA instructions.
  • Fix remaining CPU bugs (timing, instruction, etc.)
  • Sound

If you decide to take a peek at my emulator, I'd appreciate it if you could take a look over my source code. I know, it's a mess, but I'm running out of places to look for bugs. I know I'm missing some important instructions (as mentioned above) and I need to finish filling in the cycle count table that tracks how many cycles pass for each opcode. If you notice anything that isn't those, please tell me about them. Thanks. :)

I'll probably release a newer build in a few days if I fix anything.

Current download:


I also noticed something with sprite drawing. The PanDocs say sprites are drawn at the Y position specified in the OAM - 16. This doesn't work for the games I tried (Super Mario Land 1/2, Pokemon, etc), so instead, I draw them at Y - Y axis size (in the LCDC register). Most of the more complex games still don't draw correctly, like Kirby and Zelda (sprites are chopped and mashed, often drawn in the wrong position), so I'm still not sure if this is the way to do it or not.

- CHR15x94
 
Last edited:

keithodulaigh

New member
Need Help With Video :)

Hello!

Can someone explain to me how video works on the GB? I've read the "Pan document" but it has left me a bit confused...

He says the background tile map contains numbers of the tiles to be displayed and those tiles are located in the tile map at either 0x8000-8fff or 0x8800-97ff. So where on the memory map is the background tile map located?

My interpretation is that the tile map is like a "spreadsheet of tiles" and the background tile map chooses which tiles to pick from the "spreadsheet" (i.e. the numbers of the tiles).

Thanks.
 

keithodulaigh

New member
Answer to My Question

Okay I found the answer to my question.

The answer depends on the value set in the LCDC register (i.e. 0xFF40)

Bit 6 determines which address the window tile numbers are at. (These are just tile numbers, not the tile data.)

Bit 3 detemines which address the background tile number are at. (again just tile numbers, not data.)

The tile numbers are like indices for an array. You use the index to look up the data. The address of where the data lies is determined by bit 3 of the LCDC register.

For more detailed information refer to page 52 of the "Gameboy CPU manual" by Pan et al.
 

tinmanjo

New member
Hi, im going through my CPU code and something which I cant seem to get right is the Xor,Or,And etc..

for instance AF: Xor a, what is 'a' refering to.

Does this refer to RegA, RegAF so iss this correct :-

RegA=RegA Xor RegA.

Basically the tetris game I load it and get to this op, the AF=1B0, which A=1 and F=B0.

But when I debugged the same in N$gb and step AF opcode, RegAF becomes 80, how come because RegA being = 1, xor (1,1) =0.

Im confused.:(
 
Last edited:

Oldrey

New member
Game Boy Emulatrion Questions

Hi, I'm writing an emulator and I have seen different implementations of some parts of the game boy emulation so I have some questions:

1. In MBC2, when writing to address < 0x2000, the rom is trying to enable/disable external ram memory access. What I don't know is how does it work exactly: is it like MBC1, where (address & 0xF == 0xA) enables and otherwise disables, or do I have to toggle the ram enabled status (ram_enabled = !ram_enabled)? Also, in the pandocs.htm it says that bit 8 must be zero, but I have seen some emulators where they don't do this check, and some that even check that the bit is set! What's the right way of doing it?

2. In MBC2, when writing to address >= 0x2000 and address < 0x2000, the rom is trying to change the rom bank with the lower nibble of the data. I would like to know what is the behaviour if the lower nibble is zero. Do I have to change the nibble to 1 (like if the 5 lower bits are 0 in MBC1, so banks 0x00, 0x20, 0x40, 0x60 can't be used) or do I have to select bank 0, which is already in address >= 0x0000 && address <= 0x4000? Also, the pandocs.htm says that bit 8 must be 1, but again there are emulators where they ignore it or do it the other way. Which one is the correct one?

3. I'm not sure what the correct behaviour would be when ram is disabled. When the rom tries to write, should I ignore it? What does the original Game Boy do here? Also, when reading what should I return? Should I return the byte at the requested address even if ram is disabled?

4. When the rom changes rom/ram banks, should I check that they don't go out of range? And if so, what should I set them to if they are greater that the maximum number of banks?

5. The zero flag is set when the result of an arithmetic operation is 0. But suppose I'm doing an 8 bit add, for example 128 + 128. Here, the result will be 256, but when I store it in the destination register, it will be 0 (and carry flag would be set). In this case, should I set the zero flag? If not, can't the zero flag be reset unconditionally in this case, since I'm adding 2 unsigned values?

6. In the LHDL SP,n instruction, pandocs.htm says I have to set carry and half-carry flag accordingly. I'm doing an addition (sp + n) so I should set the carry flag if the result is > 0xFFFF. But since n is signed, the result could be < 0x0000. Should I check for this and set the carry flag if this condition is true? If so, I guess I should do the same for the half-carry flag? Also, I've seen here some emulators looking at the lower nibble to check for half-carry, but since sp is a 16bit word, shouldn't I be checking for the lower byte?

Thanks for your help

Edit: n is signed, not unsigned, sorry
 
Last edited:

pradipna

New member
Quite here isn't it? lol

Anyway I started making my GB emulator some days ago and after some extensive coding and debugging the emulator finally shows some thing:

ohBoy.jpg


That is the only ROM that works because I haven't handle any interrupts yet. :p Other ROMs just give white screen or show rubbish. I have so far have taken care of all opcodes (maybe some bugs, probably lol), taken care of STAT and LY registers, made a debug dumper (which basically dumps all the debug code to one big log file :p), made the frontend and yeah that's all. I should be able to finish interrupts soon and see if other roms work or not.
 

pradipna

New member
Last edited:

pradipna

New member
Thought I would post a quick update on my emu. Well, most of the 32 KB ROMs are now playable. I haven't implemented MBCs yet, and also 8*16 sprite is yet to be taken care of. I had thought of implementing MBCs after I am able to load all 32 KB ROMs perfectly but I am getting bored of bug hunting and maybe will implement MBCs soon (Hopefully Legends of Zelda: Link's Awakening will be playable soon. ;) ). Ok, here are some latest screenshots of my emu:

Tetris:

This game is now fully playable. :)

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Tetris.jpg

Amida:

This game is also fully playable.

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Amida1.jpg
http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Amida2.jpg
http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Amida3.jpg

Boxxle:

Another fully playable game. :p

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Boxxle1.jpg
http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Boxxle2.jpg

Asteriods:

The title image is scrambled. :getlost:

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Asteroids1.jpg

But playable nevertheless.

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Asteroids2.jpg

Motocross Maniacs:

This game has the most weird problem of all. It loads up just fine. But when I try to play it, after 2 seconds or so it says 'Time Up'. Maybe the timer implementation has some bugs? I have see.

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-MotocrossManiacs1.jpg
http://i2.photobucket.com/albums/y6/pradipna/OhBoy-MotocrossManiacs2.jpg

Castelian:

This game is not playable. :getlost: It loads up the title fine.

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Castelian1.jpg

But inside the game, it's just a mess.

http://i2.photobucket.com/albums/y6/pradipna/OhBoy-Castelian2.jpg
 
Last edited:

MelvoPR

New member
About the DMA Register...

I've seen some emulators that use a function between every access to memory with the purpose of intercepting where the GB wants to write to, that is, monitor when the register 0xFF46 wants to be written to.
This results in a significant overhead, due to every write, it needs to access a function. This is not necessary, you can initialize the DMA to an invalid value, that is, 0xF1 < DMA <= 0xFF. Now, when DMA changes value, it is obvious that the GB has written to it.

In other words, when DMA changes from a value less than 0xF2, we need to copy from memory[memory[0xFF46] << 8] to memory[0xFE00] (OAM) 0xA0 bytes.
As this function is supposed to take approximately 160 microseconds, we need to check for this register every ~672 cycles, assuming clock is 4.194304 MHz GB.

Implementation of above:

On initialization function:
Code:
BYTE oldDMA = 0xFF; // invalid value
mem[0xFF46] = 0xFF; // invalid value

DMA Register Check:

Code:
if(oldDMA != mem[0xFF46])
{
	oldDMA = mem[0xFF46] = 0xFF; // reset DMA reg again
	memcpy(&mem[0xFE00], &mem[(mem[0xFF46] << 8)], 0xA0); // DMA Transfer (672 cycles aprox.)
}
Note: DMA is not supposed to be read, that is, GB cannot read contents of location 0xFF46, so, this is safe to do.
 

Top