What's new

Game Boy

Sagon

New member
Hi, everyone! I'm programming gameboy emulator too. Right now i have fully implemented, but not debugged cpu, interrupts are finished at 40%. I'm now searching for a good test roms, so i'd like to know what test roms you used for your emulators?
 

HyperHacker

Raving Lunatic
The bootROM reads the Nintendo logo at $104. You need to load an actual game, then write the bootROM over the first $100 bytes. (Then when it writes 01 to $FF50, copy the start of the ROM back into that area. This is done right at $FE, so you don't need to perform a jump or anything.) If the logo or header checksum don't match it just goes into a jr-loop ($18, $FE), so you might be able to trap that and force-jump it out of the loop (modify PC manually), so that it still boots if the header is invalid.
 

aprentice

Moderator
HyperHacker said:
The bootROM reads the Nintendo logo at $104. You need to load an actual game, then write the bootROM over the first $100 bytes. (Then when it writes 01 to $FF50, copy the start of the ROM back into that area. This is done right at $FE, so you don't need to perform a jump or anything.) If the logo or header checksum don't match it just goes into a jr-loop ($18, $FE), so you might be able to trap that and force-jump it out of the loop (modify PC manually), so that it still boots if the header is invalid.

exactly what i did, did you get it working in your emu?
 

KaioShin

New member
aprentice said:
did you load a game and not the bootrom itself?

Right, that was my mistake. It is now working :saint:
Awesome work!

@Sagon: At Zophars Domain you can get a pack of PD-Roms called Test.zip (I think). These are Roms specifically for testing emus. addidtionaly I use Tetris as Test Rom as it is ROM only and seems not to complex. I must admit that I have nothing working yet, though :)

EDIT: Can someone Tell me after how many Frames Tetris Displays its first Screen??? I waited 54 Frames (due to shitloads of useless Debugoutputs this takes 2 minutes) but nothing apears on screen. I don't know if the problem is my drawing code (it's BG only atm but this screen is only BG right?) or if the rom doesn't get to load the data into the Vram area.
 
Last edited:

KaioShin

New member
bcrew1375 said:
Tetris stays on the first text screen for about 5 seconds.

You got me wrong. I don't want to know how long it stays, but after how many frames (from the beginning) it appears. The Tiles must be load into memory somewhere but my screen always stays blank. that's the prob. This counts for all games of course. if you know exactly when one of the demos loads its tiles please tell me so I can look there.
 

bcrew1375

New member
Tetris stays on the first text screen for about 5 seconds.

I didn't know the GB bootROM was dumped! I think I'll try and add support for it :D.

KaioShin: The 3-5 bits are interrupt enable registers. 3 is for H-Blank, 4 is for V-Blank, 5 is for OAM. They request an LCDC interrupt depending on the mode. So, if bit 3 is on when the mode changes to H-Blank, an LCDC interrupt is requested. You would then treat it the same as an LY Coincidence interrupt.
 

KaioShin

New member
bcrew1375 said:
KaioShin: The 3-5 bits are interrupt enable registers. 3 is for H-Blank, 4 is for V-Blank, 5 is for OAM. They request an LCDC interrupt depending on the mode. So, if bit 3 is on when the mode changes to H-Blank, an LCDC interrupt is requested. You would then treat it the same as an LY Coincidence interrupt.

Thanks a lot, that is clear now :bouncy:
Now if i'd only get some display :plain:
 

bcrew1375

New member
Yay, added support for bootROM. Runs great :D. Funny how just having the Nintendo logo scroll down makes the emu fell more authentic :).
 

ShizZy

Emulator Developer
Howdy.... been working a lot on mine latelly. Here's a shot of my emulator wip - right now I'm working on a new debugger, and disassembler (which is partly functional at the moment). As you can also see, I found another rom that was compatable! :D

Cheers
 

hap

New member
hmm, nice desktop background ;)

I just took my GameBoy out its dusty case and played some Mario1, I forgot how hard it is too see the screen without sitting under a 100watt lightbulb.
 

Sagon

New member
After two days of debugging my emulator plays normal most of 32K roms (i haven't added any MBC support), but i encountered some problems with graphics, looks like my emulator incorrect draw BG Map. I've attached some shots from Asteroids (1,2), Space Demo (3), Missile Command(4), Heiankyo Alien (5).
Any clues?

Added later:
Hmm seems like problems with my cpu emulation or smth else, but not graphics. Any ideas?

Some time later:
I've found problem, that's all because of my incorrect timing and STAT register handling.
 
Last edited:

ShizZy

Emulator Developer
Damn Sagon, you've outcoded my few months work in just a few days. I'm impressed, keep up the good work!

Edit: Disassembler is now done, and seems pretty flawless:
 
Last edited:

Sagon

New member
Thanx. By the way, i'm creating debugger too. There are still some bugs in my cpu that i can't catch, many 32K games works perfect, but in Motocross Maniacs sometimes bugs occurs.
 

ShizZy

Emulator Developer
Can someone really explain to me how exactly I should be handling the STAT register? Thanks!
 

ShizZy

Emulator Developer
Bingo. Now we're making progress.

First commercial game to boot - Tetris (Note that the first shot of Tetris, the titlescreen one, I was only to get by hacking a bit with my debugger. The rom alone crashes after the copyright screen. But it still boots :p). This and some other demos started working when I rewrote by Input/Output register code. I'm still out in the dark with my STAT stuff though.

Thanks for the help aprentice :p More to come...
 

Sagon

New member
I've finally fully debugged my cpu, now it 100% bug free :happy:
Finished my debugger, and using it fixed some bugs with my interrupts handling. Now i'm moving toward MBC emulation. Here some ingame shots:
 

ShizZy

Emulator Developer
I've done a lot of work on my emu this weekend as well. My CPU is still very much buggy - but I'm getting there. Tetris now boots and goes to the title screen on its own. (This shot is of the little preview thing that comes up when the player idles on the main screen, no in game yet :p). Asteroids now also boots, with a nasty bug - can't seem to figure that one out. I also coded some early input code for the enter key, don't know if it works but when I press it in Tetris it flickers a bit (hopefully I'm getting close). Anyways, much work to get done - still no sprites or mbc. Shots look great Sagon!
 

Sagon

New member
Good work ShizZie!
Looks like that you have a similar problem that i have with Asteroids, so maybe the further information will be useful for you.
The value that written to the STAT register shouldn't change mode bits, code might be smth like that: STAT=(STAT & 7)|(data & 0xF8). And of couse you should have a proper emulation of mode flag and lcd stuff, i've emulated it like this:
Code:
if LCD is On
{
lcd-=cycles;
special handle of vblank for LY increment
if lcd<=0
{
//handling of all modes, and of couse lcd+=next mode ticks
}
}
It work for me, hope it help you.
 
Last edited:

ShizZy

Emulator Developer
Hmmm... while it does look similiar, I think it may be different. You were able to get the first logo to work, weren't you? It's just blank for me, then the title screen fades in. I've scoured my opcodes, and I don't think the bug lies in there either. Anyways, I handle my STAT stuff pretty much the same way you posted:
Code:
			if(cpu.LCDon)
			{
				cpu.count_stat-=cpu.cycles;
				if(cpu.count_stat<=0)
				{
					switch(IOReg_STAT&0x03)
					{        
						case 0:{	// HBlank
									// --------------------------------

							// increment LY each loop  
							IOReg_LY++;	

							// LY/LYC Coincidence???  
							if(IOReg_LYC==IOReg_LY)	// LY compare
							{
								// set coincidence flag
								IOReg_STAT|=BIT_2;

								// request interrupt
								if(IOReg_STAT&BIT_6) reqINT(BIT_1);
							}else{
								// reset coincidence flag
								IOReg_STAT&=0xFB;
							}

							// time for vblank??? 
							if(IOReg_LY>144){
								vid.SetSTATMode(MODE_VBLANK);
								cpu.count_stat+=CYCLES_VBLANK;

								cpu.vblank_wait=1;

								if(IOReg_STAT&BIT_3) reqINT(BIT_1); 
							}else{ // time for mode2, OAM transfer??? 
								vid.SetSTATMode(MODE_OAMTRANSFER);
								cpu.count_stat+=CYCLES_OAMTRANSFER;


								if(!(IOReg_STAT&BIT_6) && IOReg_LYC && (IOReg_STAT&BIT_5))
								   reqINT(BIT_1);  // fixes joust, altered space, homm     
							}
						}break;

						case 1:{	// VBlank
									// --------------------------------	
													
							if(cpu.vblank_wait)
							{
								cpu.count_stat+=CYCLES_VBLANK;

								reqINT(BIT_0);

								if(IOReg_STAT&BIT_4)
									reqINT(BIT_1);

								if((IOReg_STAT&BIT_6) && (IOReg_STAT&BIT_2))
									reqINT(BIT_1);

								// ----------
								// joypad interrupt shit here
								// ----------

								cpu.vblank_wait=0;
							}

							if(IOReg_LY<153){
								++IOReg_LY;

								if(IOReg_LY>=153) cpu.count_stat+=24;
								else cpu.count_stat+=CYCLES_VBLANK;
							}else{
								// update user input
								EventSDL();

								// reset the LY register
								IOReg_LY=0;

								// goto mode2, oam transfer 
								vid.SetSTATMode(MODE_OAMTRANSFER);
								cpu.count_stat+=CYCLES_OAMTRANSFER;
							}

							// LY/LYC Coincidence??? 
							if(IOReg_LYC==IOReg_LY)	// LY compare
							{
								// set coincidence flag
								IOReg_STAT|=BIT_2;

								// request interrupt
								if(IOReg_STAT&BIT_6) reqINT(BIT_1);
							}else{
								// reset coincidence flag
								IOReg_STAT&=0xFB;
							}	
						}break;

					case 2:{	// Searching OAM...
								// --------------------------------

							cpu.count_stat+=CYCLES_OAMTRANSFER;

							cpu.draw_wait = 12;

							// next mode...
							vid.SetSTATMode(MODE_TRANSFER);
							cpu.count_stat+=CYCLES_TRANSFER;

							break;}
							
					case 3:{	// Transfer
								// --------------------------------

							cpu.count_stat+=CYCLES_TRANSFER;

							// next mode..
							vid.SetSTATMode(MODE_HBLANK);
							cpu.count_stat+=CYCLES_HBLANK;

							if(IOReg_STAT&BIT_4)
							reqINT(BIT_1);

							break;}
					}
				}

				if(cpu.draw_wait)
				{
					cpu.draw_wait -= cpu.cycles;
					if(cpu.draw_wait <= 0)
					{
						cpu.draw_wait = 0;
						if(IOReg_LY < 144)
						{
							vid.DrawScanline();
						}
					}
				}
			}

And here is my STAT adjust function:

Code:
	void VIDEO::SetSTATMode(int mode)
	{
		IOReg_STAT=(IOReg_STAT&0xFC)|mode; //Clear and set bits 0,1
		switch(mode)
		{
			case 0: //HBlank
				dbg_lcdc_phase=1;
				if(IOReg_STAT&0x08) IOReg_IF|=BIT_1;
				break;
			case 1: //VBlank
				dbg_lcdc_phase=4;
				if(IOReg_STAT&0x10) IOReg_IF|=BIT_1;
				break;
			case 2: //OAM
				dbg_lcdc_phase=2;
				if(IOReg_STAT&0x20) IOReg_IF|=BIT_1;
				break;
			case 3: //Transfer
				dbg_lcdc_phase=3;
				//if(cpu.hdma&0x80) hdma_hblank();
				break;
		}
	}

Any ideas?

Edit: I see what you mean by writing to STAT in the form of STAT=(STAT & 7)|(data & 0xF8), tried it. Results are the same though.
 
Last edited:

Top