Sign in to follow this  
  • entries
    177
  • comments
    531
  • views
    163637

Apex

Sign in to follow this  
Scet

333 views

Yes that's right, I'm not dead. I just haven't done anything over the summer, but now that my summer job is over, I have returned to programming. One thing I realized though was that I can never really make a game by myself since I have no artistic talent and lack the money to hire people with talent. So I'm back to working on my GBA emulator.

I'm not basing this one off my previous C++ GBA emulator FatMan, instead this one will be written in C# and feature a few new improvements to make it at least fast enough to runs games at there proper speed. The name of the new emulator is Apex.

The magical GBA JIT

For those of you that don't know anything about ARM processors(probably everyone), the ARM is a RISC processor that stores every opcode as a 32-bit number. This number contains varies bitfields that contain what conditions, registers and data are used in the opcode. This can make decoding them in software quite expensive. In FatMan I decoded each instruction every time it was executed, probably why it was so damn slow. Apex uses a kind of JIT system which only decodes each instruction once, unless the processor switches states or I use the disassembler.

Each memory bank as a structure like this:


private byte[] DataArray;

private int Mask;

private Processor.IOpcode[] OpcodeArray;

private int Size;




The OpcodeArray is the same size as the DataArray, although it's impossible to make an unaligned jump, this speeds things up by not having to mask the address all the time.

If you're wondering why every part of memory has an opcode and not just the cartridge ROM, it's because the processor can jump to anywhere in memory and many commercial cartridges use the external RAM because it's data bus is 32-bits and the ROMs is only 16-bit.

The ARM also contains a second smaller instruction set called THUMB where each opcode is 16-bits, half the size. In an actual ARM chip these THUMB instructions map to their ARM counterparts, I've done something similar in Apex.

Here is the MUL instruction, notice how all the decoder work in done in the constructor and the Execute method is the same for both ARM and THUMB states.


public abstract partial class Opcode
{

public class MUL : Opcode, IOpcode
{

private uint Rd = 0;

private uint Rm = 0;

private uint Rs = 0;

private bool SetFlags = true;

private MUL( ref Processor.Modes Mode, ref uint Value ) : base( ref Mode, ref Value )
{
if( Mode == Processor.Modes.ARM )
{
SetFlags = ( ( Value & 0x00100000 ) == 0x00100000 );
Rd = ( Value >> 16 ) & 0x0F;
Rs = ( Value >> 8 ) & 0x0F;
Rm = Value & 0x0F;
}
else
{
Rd = Rm = Value & 0x07;
Rs = ( Value >> 3 ) & 0x07;
}
return;
}

public static MUL Create( ref Processor.Modes Mode, ref uint Value )
{
return new MUL( ref Mode, ref Value );
}

public override string Disassemble( int Address )
{
if( Mode == Processor.Modes.ARM )
{
return base.Disassemble( Address ) + String.Format( "MUL{0}{1} R{2}, R{3}, R{4}", ( Condition != Conditions.AL ) ? Condition.ToString() : "", SetFlags ? "S" : "", Rd, Rm, Rs );
}
else
{
return base.Disassemble( Address ) + String.Format( "MULS R{0}, R{1}", Rd, Rs );
}
}

public int Execute()
{
unchecked
{
Register.Array[Rd] = Register.Array[Rm] * Register.Array[Rs];
if( SetFlags )
{
Register.Flag.N = ( ( Register.Array[Rd] & 0x80000000 ) == 0x80000000 );
Register.Flag.Z = ( Register.Array[Rd] == 0 );
}
}
return 0;
}

}

}




Graphics

This time around I'm using full hardware accelertion, instead of FatMans method of software rendering. I've only gotten to mode 4 so far though and I haven't implemented a proper per-scan line renderer, so the speeds you see here really don't mean anything.

Anyway the graphics will use a simple shader system for palette effects. Modes 0, 1, 2 will have there backgrounds in A8L8 format and modes 3, 4 and 5 will use the L8 format(since they only have one background), sprites will also use A8L8. Unfortunatley my video card does not support the X1B5G5R5 format and I have to use the X1R5G5B5 format for the palette and the swap the red and blue components in the shader.


float4x4 WorldViewProj : WORLDVIEWPROJ;

Texture ColorTexture;

sampler ColorTextureSampler = sampler_state { texture = ; magfilter = NONE; minfilter = NONE; mipfilter = NONE; AddressU = wrap; AddressV = wrap; };

Texture PaletteTexture;

sampler PaletteTextureSampler = sampler_state { texture = ; magfilter = NONE; minfilter = NONE; mipfilter = NONE; AddressU = wrap; AddressV = wrap; };

struct a2v
{
float4 Position : POSITION0;
float2 TexCoords : TEXCOORD0;
};

struct v2p
{
float4 Position : POSITION0;
float2 TexCoords : TEXCOORD0;
};

struct p2f
{
float4 Color : COLOR0;
};

void vs( in a2v IN, out v2p OUT )
{
OUT.Position = mul( IN.Position, WorldViewProj );
OUT.TexCoords = IN.TexCoords;
}

void ps( in v2p IN, out p2f OUT )
{
float4 TextureColor = tex2D( ColorTextureSampler, IN.TexCoords );
OUT.Color = tex1D( PaletteTextureSampler, TextureColor.r );
OUT.Color.a = OUT.Color.r;
OUT.Color.r = OUT.Color.b;
OUT.Color.b = OUT.Color.a;
}

technique PaletteTechnique
{
pass p0
{
vertexshader = compile vs_1_1 vs();
pixelshader = compile ps_1_4 ps();
}
}




I once again ripped out some of Dooms VRAM using VisualBoyAdvance.

Before shader:


After:


AGAIN I'M NOT RUNNING DOOM!!! It's just a VRAM dump to test the graphics, some people last time couldn't figure this out.
Sign in to follow this  


3 Comments


Recommended Comments

I've missed this journal - good to see it back in action! [smile]

Interesting design of the opcode class. What's performance like?

Share this comment


Link to comment
Quote:
Original post by Ravuya
YOU'RE, LIKE, PLAYING DOOM.


Die in a fire.

Quote:
Original post by benryves
Interesting design of the opcode class. What's performance like?


I can't really emulator anything yet so I really don't know. I've done a few speed tests on memory access, my JIT system and interfaces vs virtual functions and it looks like it should be able to run a game at full speed. Still haven't taken into account the graphics code though.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now