• entries
177
531
• views
163820

Emulation goodness inside

## Last Post

Well apparently my GDNet+ stuff still works, I canceled it since I don't post much any more, maybe there's some grace period or something.

I haven't done much over the summer since I'm so tired after work. My only real progress has been separating GameKnight into two projects, the Windows executable and an API independent library. I did this because back in May someone e-mailed me about porting it to XNA to run on the Zune, and was having trouble separating the emulation and Windows code.

The new release(0.21) in on the CodePlex page, but it's pretty much the same as the 0.2 one except for the way the code is organized. Hopefully I'll get around to adding sound support soon.

Also news of the project has somehow reached several emulation sites. I don't know how as I've only posted about it here, but GameKnight 0.2 got 158 downloads versus 0.1s measly 14.

This will likely be my last post here, so I'd like to thank everyone that stopped by, even though some of you(Hopedagger, Rob Loach) seem to have disappeared from GD. Since I don't have any new screenshots and since every post has to have a picture, Jon Arbuckle will once again have to fill in:

## Look! It's another crappy Beta!

Wow, not a single post in April. My focus on school did pay off though, four A's and one D(I was expecting an F so this is good). Anyway my burn out is wearing off and I've started to work on GameKnight again.

This release(0.2) adds save states and a crappy dialog window to change keys.

Unfortunately save states currently only work original GameBoy games, when loading the color ones, a portion of the VRAM seems to get screwed up.

Here's the hastily made dialog box, I'll add mouse and joystick/gamepad support later. Hopefully my old Gravis GamePad(it looks like an SNES controller) with its ancient DB15 connector will work.

## Laugh at my source codes!

I've setup a CodePlex page for GameKnight(yes we're back to GameKnight, no more GreatNES). The binaries and source are in separate zips since CodePlex doesn't have an option to label a file as both. I was also planning on going with the zlib/libpng license, but CodePlex limits the licenses you can select and I went with the MIT license instead, oh well.

Go give it a whirl so I know if works or doesn't work on your system(system specs would be nice). You should get around 60 FPS, anything else and it means either your computer sucks or my timing code sucks, probably both. Actually I've been having problems with GameBoy Color games that run in double speed mode, seems my 2Ghz machine can't handle an 8Mhz Z80. If you'll looking for some ROMs, Mr. Zophar has a couple you can use.

Still haven't gotten around to adding anything thanks to heaps of school work. School ends in three weeks and I plan to take a one week break(I'll need it) before starting my summer job, so hopefully I can add sound and save states then.

I'm blaming Ravuya and so should you.

## Total Lack of Progress

It's been over two weeks since the last update, so I thought I should update this thing. Unfortunately I haven't been able to get much done in that time, it's the last couple weeks of school and I'm buried in tests, assignments and projects. There's some sound code, but not enough to actually make any sounds and I've been able to get the other GameBoy Color games to run, although most of them are unplayable.

Here's Mega Man Xtreme 2:

X looks like he just teleported into some demented Tetris game.

The Zelda Oracle games now just generate a black screen [sad].

I'll probably get back into it soon. I wanted to finish this before the summer break, but it doesn't look like it's going to happen, hell I thought it would be finished back in October(what's the saying, "the last ten percent"?).

After all this is sorted out I plan on going back to either Doom.Net or adding in the GBA to the emulator, I think I'll save the NES for later.

## In Living Color Part 2

Well I fixed the rather trivial bugs, most of which where a pain to find due to all the changes I made.

The first one was pretty embarrassing, basically I was using windows calculator to find a the right shift amount for 0x2000 and used 1 << 0xD, but I forgot my hex for a second and put 1 << 14 in my program so all the reads/writes to the upper 8KB of VRAM failed.

The palette issues where simply because I was doing the 15bpp to 32bpp conversion at the wrong time. My code uses A8R8G8B8 for everything, but the GameBoy Color uses X1B5G5R5. I could use the same format, but someday I'd like to implement a tile editor/viewer and have it work for all systems so it's easier just to stick with 32bpp.

Finally the problem with the old GameBoy games, was that I forgot about the changes in RAM size between systems. The GameBoy Color has 8 4KB banks of internal RAM, but the older version only has 8KB. With the older games I was only accessing the first 4KB.

Anyway, enough talk. Here's what you came here for:

I can't get the damn Oracle series to work. Seems it still thinks it's running on an old system.

I've also broken Kirby's Dream Land 2 again and the star in Super Mario Land doesn't work. I've dealt with that bug numerous times though and it has to do with the timer interrupt. Damn interrupts and their finicky timing!

Edit: Nevermind, fixed that as well.

## In Living Color

I've given up trying to track down every little bug for now, and have started working on sound and GameBoy Color features. Unfortunately information on both is extremely scarce so this may take a while.

I have color support kind of working. The extra memory and color palettes are in, but some of the tiles seem to reference the wrong palette.

Maps I'm not surprised don't work, I didn't expect them to. However the sprites should be correct.

Also I've been making some heavy changes to the design, nothing that's required a rewrite, however all this new color stuff seems to have completely broken all the old games. I can't play a single one and the few that at least start mess up after a few seconds. [sad]

## Synchronization hell

I've squished a few more bugs and have almost all the games working now. Most still have some graphical problems, likely due to timing. There are also two games I continue to have trouble with, Mortal Kombat which refuses to pass the "presented by Midway" screen and Super Mario Land 2, which won't go past the title screen. Yes I know it was working last entry, but it's a finicky bastard.

The first bug and the one that has been causing all the games to flicker, was that I wasn't copying enough bytes for the sprite DMA. Part of the problem here is the documentation:

Quote:

## BEWARE I LIVE

Yeah sorry, I'll post some actual development stuff tomorrow. I needed something to post of Halloween and unfortunately I didn't have time to do another Doom inspired pumpkin like last year, plus I had to show off [smile].

## Demo #2

Well here it is. This version improves the interface(no more command line) and features better LCD timing. Almost all games now start up, although most are only playable for a few seconds before they go all screwy [sad]. I've included a few PD ROMs in the demo, however for some reason "They came from outer space" works when I run the emulator from the IDE, but is buggy when run normally.

Edit: Forgot to list the keys AGAIN

Enter = Start
Select = Space

Sample screenshots:

I finished rewriting the code a few days ago, but unfortunately there where a few bugs that stopped anything from running properly.

After days of stepping through numerous games code with the disassembler, the problem turned out to be that I placed Memory.WriteUInt16 instead of Memory.WriteByte in the LD (HL), A instruction.

Everything's back to normal now, expect a new demo sometime this weekend.

As you can the interface hasn't really changed. I opted to stick with just doing a simple GameBoy emulator instead of the plug-in MDI based system I talked about in the last entry.

Also I'm becoming fed up with the GDNet+ service as I've had to resort to using my old PhotoBucket account to host images. The bloody GDNet+ web space isn't working and hasn't been working for me for two days now. This isn't the first time this has happened either.

It's no mystery why people are moving their journals to other sites. If this bullshit continues, this will be my last year as GDNet+.

## The new and improved Apex

I've started working on a new emulator application, named Apex just like the GBA emulator I was working on. Basically it's a MDI application with a plug-in based system that loads various game systems via .NET DLLs with reflection. The first system to be added will of course be the GameBoy.

It's going to take a while though before I have any fancy screenshots. Unlike the previous emulator this one is meant to work with a number of different systems. Because of this I'm building a Z80 core first, which I will then inherit off of to build the GameBoys processor(a smaller version of the Z80).

The opcode class also makes use of inheritance to eliminate the amount of repetitive code, for example here are the 8-bit versions of SUB, SBC and CP:

SUB:
using System;namespace Apex{		public partial class Z80	{				protected partial class Opcode		{				public unsafe abstract partial class Arithmetic8bit : Opcode			{								public class SUB : Arithmetic8bit				{										protected int Carry = 0;										protected bool WriteResult = true;										public SUB( int Value ) : base( Value )					{						return;					}  						public override int Execute( Z80 Processor )					{							base.Execute( Processor );						Pair Temp = new Pair( Processor.A.Value - *Pointer - Carry );							Processor.SetFlags( Flags.Negative );						Processor.AddFlags( Flags.Parity, ( ( Processor.A.Value ^ *Pointer ) & ( Processor.A.Value ^ Temp.LowerByte.Value ) & 0x80 ) );							Processor.AddFlags( Flags.Carry, Temp.UpperByte.Value );						Processor.AddFlags( Flags.HalfCarry, ( ( Processor.A.Value ^ *Pointer ^ Temp.LowerByte.Value ) & 0x10 ) );												Processor.AddFlags( SZ_Table[Temp.LowerByte.Value] );												if( WriteResult )						{							Processor.A.Value = Temp.LowerByte.Value;						}						return Cycles;					}									}							}					}			}	}

SBC:
using System;namespace Apex{		public partial class Z80	{				protected partial class Opcode		{				public unsafe abstract partial class Arithmetic8bit : Opcode			{								public class SBC : SUB				{										public SBC( int Value ) : base( Value )					{						return;					}  						public override int Execute( Z80 Processor )					{							Carry = ( Processor.GetFlag( Flags.Carry ) ? 1 : 0 );						return base.Execute( Processor );					}									}							}					}			}	}

CP:
using System;namespace Apex{		public partial class Z80	{				protected partial class Opcode		{				public unsafe abstract partial class Arithmetic8bit : Opcode			{								public class CP : SUB				{										public CP( int Value ) : base( Value )					{						WriteResult = false;						return;					}									}							}					}			}	}

Basically if there's a problem with one of the opcodes, fixing it also fixes the others based on it. All the different address modes are also covered by the same function. Here is the Arithmetic8 class that all the 8-bit math operations inherit of off:

using System;namespace Apex{		public partial class Z80	{				protected partial class Opcode		{				public unsafe abstract partial class Arithmetic8bit : Opcode			{								protected byte* Pointer = null;															public Arithmetic8bit( int Value ) : base( Value )				{					switch( Value >> 8 )					{						case 0xDD:							AddressMode = AddressModes.IndirectIndexedX;							Cycles = 19;							break;						case 0xFD:							AddressMode = AddressModes.IndirectIndexedY;							Cycles = 19;							break;						default:							if( ( Value & 0x07 ) != 0x06 )							{								AddressMode = AddressModes.Register;								Cycles = 4;							}							else							{								if( ( Value & 0x40 ) == 0 )								{									AddressMode = AddressModes.RegisterIndirect;								}								else								{									AddressMode = AddressModes.Immediate;									}								Cycles = 7;											}							break;					}					return;				}								public override int Execute( Z80 Processor )				{					switch( AddressMode )					{						case AddressModes.Register:							if( ( Value & 0xC0 ) != 0 )							{								Pointer = Processor.GetRegisterPointer( Value & 0x07 );							}							else							{								Pointer = Processor.GetRegisterPointer( ( Value >> 3 ) & 0x07 );							}							break;						case AddressModes.RegisterIndirect:							Pointer = Processor.Memory.GetPointer( Processor.HL.Value );							break;						case AddressModes.Immediate:							Pointer = Processor.Memory.GetPointer( Processor.PC.Value++ );							break;						case AddressModes.IndirectIndexedX:							Pointer = Processor.Memory.GetPointer( Processor.IX.Value + Processor.Memory.ReadSignedByte( Processor.PC.Value++ ) );							break;						case AddressModes.IndirectIndexedY:							Pointer = Processor.Memory.GetPointer( Processor.IY.Value + Processor.Memory.ReadSignedByte( Processor.PC.Value++ ) );							break;					}					return 0;				}							}					}			}		}

In GameKnight each opcode had different classes for each address mode, so there where hundreds of files just for the opcodes, most of which had exactly the same code except for a couple lines. The goal of the emulator this time isn't speed, but to be easy to debug and maintain.

## Demo Time!

I've implement mapper 3 and 5 so the only mappers left are the special Hudson and Bandai ones. With these two mappers all the Pokemon games along with Ghosts 'N Goblins now work, although Ghosts 'N Goblins suffers from seizure inducing sprite flickering.

Sprite multiplexing may work on the GameBoys LCD, but it doesn't work on a computer [sad]

Demo:

I'm releasing what I have now because the whole thing needs to be rewritten. It's not that it doesn't work, but I'd rather do it now then later. Basically the design is horrible, the code is full of public statics, classes can access things that they shouldn't be able to.

Anyway download the program here. It's a command line program right now, if you don't know what that means just drag the files into the executable. You'll need .Net 2.0 and Managed DirectX installed, although I plan on trying to switch over to SlimDX during the rewrite.

You can get public domain ROMs over at Zophar's. I tested "GB Lander", "The Horrible Demon 3" and "They Came From Outer Space" and they all worked.

Edit: Sorry I forgot to include what the keys are.

Enter = Start
Select = Space
A = A
S = B

Yeah I don't know how it'll work on non-QWERTY keyboards.

## Almost there

Small update today. I've implemented windowing so status bars now work along with finally fixing the palette issues. Still need to work on sprite priority.

Should have a demo ready sometime this weekend.

## ARM CANNON FTW

I've gotten more games to run and a few are now completely playable thanks to squashing a retarded bitwise bug in one of the jump opcodes. This is the problem with making an emulator, all it takes is one little mistake in one opcode hidden away and nothing will work right. It doesn't just crash either, it just executes garbage, making it a pain in the ass to debug.

Anyway the first game to actually run without any game play errors was Super Mario Land.

Zelda is also playable:

Unfortunately the only playable Mega Man game is Mega Man 2. Mega Man 1 will get past the title screen now, but freezes when the screen scrolls vertically.

Yeah he thought he was all that, but I beat him without even having the health bars.

As you can see there are still plenty of graphical issues to work out. I need windowing support to get the status bars to work and obviously the palettes are still all screwy.

## Le Progress

After implementing mappers 1 and 2 along with all the interrupts I've been able to run a few more games. Unfortunately "run" doesn't mean "play", most games fail to get past the title screen.

I can play a couple games though:

Every game seems to have sprite issues though. Mega Man seems to load sprite RAM with garbage and doesn't display anything, the pacman demo requires a bunch of palette hacks and in asteroids the ship sprite gets all messed up on some of the rotations.

## HOLY SHIT IT WORKS!!!!!!1

Yep I've actually been able to emulate something. Not much really, just a simple 32KB public domain ROM, but it's a good start. I'll be implementing the memory mappers over the weekend and trying to run something bigger.

I've also been working on the various debugging tools for the emulator. The only one that's finished is the disassembler, which I finished about an hour ago and helped in fixing a few broken opcodes to get the above program running.

Edit: Just did a speed test. Around 18000000 instructions per second before it drops below 60FPS at 3x resolution, more than enough.