Thursday, February 26, 2009

Some advances

I've been working on the Sprites support and they seem to be working pretty good. I also have worked on the Windows, Background and main Screen and now I am able to show some pics as if they were on Gameboy's main screen :)

I'm sorry again for not updating.. my final report has taken more time of me than expected. I've finished all my work today but I still have to put the final details to the report so I'm not completely free, but I should be free tomorrow and with plenty of time to write a couple of entries.

Here is a pic that shows the background and a couple of sprites :p

Wednesday, February 25, 2009

Trumped up excuses...

Well.. I didn't write yesterday because I had my Final Presentation for my Summer Student Work today.. And I used my spare time to write a debugger for my emulator!

I will add a new section tomorrow or maybe later. For now I'll talk about debuggers.. Having a good debugger is really a help tool to check the errors of your emulator. Being able to break the execution at a certain instruction, doing a step to step check and some other fancy stuff is always of great help to find the small errors in your emulator.

Until now I was using the debugger that comes with Visual Studio 2008, it is a quite good debugger I must say but using it to debug a sub "program" gets a little complicated. It's true that I had a watch on each of the CPU Registers, 10 entries from the Stack(around the current SP), 10 entries from the memory(around the current PC) and other stuff. But doing the steps takes a little longer and breaking the execution at a given point gets really difficult. At some point I used some strategies to do this, but I really hated them, so I had to make my debugger..

It is really basic for now. It can take single steps, reset the cpu, start, stop, break at given PC(only one instruction, multiple coming soon!). I'd like to add this multiple breaking points resource as well as being able to change values in runtime. I now how to do both of them(I think) but I just need some time to do that. I still have to do my final report and organize everything here at the office.. and I will use some time for sports since last week I almost did nothing.

Enough complaining.. here is a picture of the debugger!



I forgot to stop it so it haven't updated the current instruction!

Monday, February 23, 2009

The Memory

The memory itself is really easy to implement. It's just an array of values of the needed size. We could create the memory at compile time (i.e type mem[SIZE];) but just to make sure the compiler lets use the amount of memory needed we will do it dynamically. We should know that the compiler limits us in the static memory allocation size but not in the dynamic one, though the last one may fail due to lack of free memory in the system, but that shouldn't happen anyway.

So I implement it like this:
    1 #define MEMORY_SIZE 0x10000
2 UINT8 mem*;
3 mem = new UINT8[MEMORY_SIZE];
4 if(mem == NULL)
5 exit(-1); //Oops we ran out of memory!

There we have a fully functional memory for the GB! But well, it is not as simple.
Our memory is separated in different sections which are meant to do different things. For example it has the ROM, RAM, Tile Data, Tile Map, Sprites, Internal Registers, VRAM, I/O space, etc. and because of that we can't treat all memory the same.

Luckyly we can get around this problem and act as needed given the proper memory address. We have two actions that can be done on the memory: Read and Write. And each of those could act different depending the address they are intending to interact with. So we'll need a memory map that takes care of this.

First we define the basic structures to do this task. This are the Memory Handlers:
    1 struct readMem
2 {
3 UINT32 startAddress;
4 UINT32 endAddress;
5 UINT8 (*memoryHandler) (UINT32);
6 void *pUserData;
7 };
8
9 struct writeMem
10 {
11 UINT32 startAddress;
12 UINT32 endAddress;
13 void (*memoryHandler) (UINT32, UINT8);
14 void *pUserData;
15 };

Reading and writing structures are very similar but they differ in the function pointer because the read returns a value whereas the write receives a value, and of course both receives the address they want to affect. The start and end Addresses mean the range in which a given Handler will be called. So you will have a specific handler for each different behaviour when reading and/or writing.

So.. what kind of behaviour do I refer to? For example in the GB when writing to an address which is in the ROM range won't write, but rather try to change the Switchable ROM bank.

The function that gets called would be something like this:
    1 void writeROMBankSelect(UINT32 address, UINT8 data)
2 {
3 data = data & 0x1F; //Just uses 5 bits for this (max 32 banks).
4 if(data <= gb->rom.rom_b.n) //If there are enough banks in the rom.
5 memcpy(gb->mem.mainMemory + gb->rom.rom_b.size,gb->rom.rom_b.banks[data],gb->rom.rom_b.size); //Copy the ROM bank to the MainMemory.
6 }

There is some additional handling(i.e. banks 1,21,41 and 61 can't be used) but that's the main idea.

The address for this Handling function is 0x2000 to 0x3FFF. The rest of the addresses have their own handling functions yielding to a memory handler like:
    1 writeMem implWriteMem[] =
2 {
3 { 0x0000, 0x1FFF, writeRAMBankEnable, NULL},
4 { 0x2000, 0x3FFF, writeROMBankSelect, NULL}, //This one!
5 { 0x4000, 0x5FFF, writeRAMBankSelect, NULL},
6 { 0x6000, 0x7FFF, writeRAMROMModeSelect, NULL},
7 { 0x8000, 0x9FFF, writeVRAM, NULL},
8 { 0xA000, 0xBFFF, writeSRAM, NULL},
9 { 0xC000, 0xDFFF, writeRAM, NULL},
10 { 0xE000, 0xFDFF, writeERAM, NULL},
11 { 0xFE00, 0xFE9F, writeSprite, NULL},
12 { 0xFF00, 0xFF7F, writeIOM, NULL},
13 { 0xFF80, 0xFFFF, writeHRAM, NULL},
14 { (UINT32) -1, (UINT32) -1, NULL, NULL }
15 };

This just creates an static array of the structure defined before(struct writeMem).

Ok.. now we have the handlers, but how do we use them? There are functions for this, which are:
    1 UINT8 data readByte(UINT32 address);
2 void writeByte(UINT32 address, UINT8 data);
3
4 UINT16 data readWord(UINT32 address); //Read 2 bytes
5 void writeWord(UINT32 address, UINT16 data); //Write 2 bytes

There are operations in the gameboy which reads or writes in pair, for the AF, BC, DE and HL mixed registers and as well for the SP and PC registers so the 2 bytes read and write come in handy.

So then when we want to read something is as simple as
data = readByte(address);
But let's get in the implementation of these functions:

The different functions work in similar way, so I will show how the writeByte(..) works:
    1 void writeByte(UINT32 address, UINT8 data)
2 {
3 writeMem *last; //Last handler being checked for valid address.
4 UINT32 i = 0;
5 last = &amp;(mem_h->WMem[i++]); //Update pointer.
6 //While there are handlers left.
7 while ((last->startAddress != (UINT32)-1) &amp;&amp; (last->endAddress != (UINT32)-1)){
8 //If address is in range.
9 if((address >= last->startAddress) &amp;&amp; (address <= last->endAddress)){
10 //If there is a handler
11 if(last->memoryHandler != NULL){
12 //Call the function
13 (*(last->memoryHandler))(address, data);
14 return;
15 }
16 else{ //If not use the user data.
17 ((UINT8 *) last->pUserData)[address] = data;
18 return;
19 }
20 }
21 else //If not, update pointer.
22 last = &amp;(mem_h->WMem[i++]);
23 }
24 mem->mainMemory[address] = data; //If there is no specific handler
25 //Access the memory directly.
26 }

So the idea is simple. Search for the entry in the array of Handlers which is supposed to handle the given address. If there is one, and you have a function pointer, then call it. If there's no such function pointer then use the user data pointer(pointer to some memory type). Now.. if there is no handler for the given address, then access the memory directly.

This code is effective and flexible, but I think it has a couple of issues in performance. I will use it for now, until I get to a good point with the emulator and I run a profiler to check what to optimize. I'm sure this will appear in the optimization list.

In the CPU post I talked about initializing some values besides the CPU registers. Well, we can do that now. That's not exactly from this section but I wouldn't create a section for it. So an example(there are a lot of values) would be:
    1 writeByte(0xFF05, 0x00);
2 writeByte(0xFF06, 0x00);
3 writeByte(0xFF07, 0x00);
4 writeByte(0xFF10, 0x80);
5 writeByte(0xFF11, 0xBF);
6 ...
7 writeByte(0xFFFF, 0x00);

I think that summarizes the Memory Mapping and Handling.

The CPU

At last we are getting to the coding!

The first important thing is to realize what would the CPU need. You can forget to put some stuff as you can add them later, but the sooner you realize what you need, the better you understand the console.

So let's see what has the GB CPU:

- 8 Registers of 1 byte which could be used as 4 2 bytes Registers.
- The Stack Pointer(SP) Register.
- The Program Counter(PC) Register.
- The Interruption Master Enabled(IME) Flag.

When I started the cpu design I didn't put the IME flag because I didn't understand too well how it worked, and if it was part of the CPU or a part of the memory. Then when getting to handle the interruptions I realized it was part of the CPU so I added it.

Let's talk about the Registers. We have the A, F, B, C, D, E, H and L registers. Each of them could be handled by an unsigned char type. But we have the problem that they can be paired to be 2 bytes Registers. A solution could be to replicate the data(i.e. AF = A << 8 F)

typedef union
{
UINT16 w;
struct
{
UINT8 l;
UINT8 h;
}b;
}cpuReg;
cpuReg AF;

The UINT8 is just a #DEFINE UINT8 unsigned char.
The UINT16 is just a #DEFINE UINT16 unsigned short.

So here to access AF we would use AF.w and to access A or F it would be AF.b.h and AF.b.l respectively. The great advantage with the union solution is that they share the same memory so changing one value changes the other.

Another solution could be done with pointers to make them work in a similar way as union does.

The SP and PC Registers are just UINT16 types.
In my case I'm using IME as a bool as it just says if interruptions are enabled or not.

The Register F is special one. It doesn't let you change it directly, because is a register that stores the flag status. It has the flags


Flag Bit Name Description
Z 7 Zero Set when the last operation yielded 0 as result.
N 6 Sub Set if last operation was a substraction.
H 5 Half Carry Set when there's a carry from the 3 bit to the 4 bit of the last operation.
C 4 Carry Set when there's a carry on the 7 bit.


Besides the "official" meaning, the flags gets set or reset in other situations depending on the command and the parameters. You have to obtain that information from somewhere. Usually the information that developers use to create the games will have the correct behaviour of the different commands.

The general cpu structure will be something like:


typedef struct
{
cpuReg AF;
cpuReg BC;
cpuReg DE;
cpuReg HL;
UINT16 SP;
UINT16 PC;
bool IME;
} CPU;
typedef CPU* pCPU;
Pretty simple, isn't it? Well, we still have to handle all the operations of the CPU but that will be in other section since we still need access to the memory.

I've added some defines to get and set(or reset) the values of the flags:

//Get the flags
#define flagZ ((cpu->AF.b.l & 0x80) >> 7)
#define flagN ((cpu->AF.b.l & 0x40) >> 6)
#define flagH ((cpu->AF.b.l & 0x20) >> 5)
#define flagC ((cpu->AF.b.l & 0x10) >> 4)
//Set and Reset the flags
#define SetZ cpu->AF.b.l |= 0x80
#define ResetZ cpu->AF.b.l &= 0x7F
#define SetN cpu->AF.b.l |= 0x40
#define ResetN cpu->AF.b.l &= 0xBF
#define SetH cpu->AF.b.l |= 0x20
#define ResetH cpu->AF.b.l &= 0xDF
#define SetC cpu->AF.b.l |= 0x10
#define ResetC cpu->AF.b.l &= 0xEF


Then the CPU has to initialize the register values and some memory values that are used as special registers.

In the case of the Monochrome GB the initial values of the base Registers of the CPU are:


cpu->AF.b.h = 0x01; //A
cpu->AF.b.l = 0xB0; //F
cpu->BC.w = 0x0013; //BC
cpu->DE.w = 0x00D8; //DE
cpu->HL.w = 0x014D; //HL
cpu->SP = 0xFFFE; //SP
cpu->PC = 0x0100; //PC
cpu->IME = false; //IME


And we are ready to move on!

General Design

Well the first thing you should do is a general design, but as I have experienced, at first you will most probably do a design that don't fit all requirements, probably because you didn't know all the things you will need. But still, without an initial design, you won't make your program.

My design is pretty simple and somewhat modular; I have the functionalities separated by files:

myemu: This is the file containing the main. It initializes the Window, DirectX (or other video API) and calls the initGB() function. After that it keeps receiving windows messages.

console: Console has the main code of the emulator. Like the fetching of the opcodes, the video writing to the framebuffer and so.

cpu: Has the code directly related with the CPU. Registers, initial values, etc.

memory: Has the code related to the memory, memory map and memory handling.

rom: Has code to initialize the rom and stores all the information in a structure.

video: This file is in charge of doing tasks as acquiring the tile data, sprites and other

dx: This file has all the DX initialization, use and destruction.

There are still a couple of things "mixed", but mainly because they can be in more than one category.

Where to start?

One of the most asked questions that appears about developing a console emulator is where to start. The truth is that this question gets asked so much because it's really an important and variable one. It depends on many things, such as the knowledge of the target system and the programming knowledge. One thing is for sure, without great knowledge on the target system and good to great knowledge on a programming language you won't be able to make the emulator you desire, but you can definitely learn as you need.

The other common question is which programming language to use. I really think that if you just want to do an emulator for fun or learning you can use whatever language you want as they probably are all capable handling such a task. Though I wouldn't like to see the code of an emulator developed in Prolog or Scheme. But then we come to another important side, which relates to how well your emulator behaves. Even if it is possible to make the emulator in any language, it certainly won't run as fast in all of them, and that's the main reason why the most recommended language for this kind of tasks is C/C++. It allows for low level coding which helps to improve the performance of the emulator.

I have always liked C and in the last time have worked a lot with C++ and got to like it too. So that was the language of choice for me. I feel comfortable with it and there's tons of documentation and APIs to help with other tasks (mainly Input, Video and Sound).

So which API do we use for the Video? The truth is that you should use what you think is the fastest and or easier one but trying to do your emulator in such way that is easy to change from one API to another doing the minimal changes. This usually could be done by wrapping the API calls. In my case I've chosen DirectX (which made me code in windows) because I have worked before with both OpenGL and SDL and just little really basic stuff with DirectX and I thought it would be good to learn the most in the process of developing the emulator.

Now.. if you lack the programming skills in an especific language that you choose I will point you to learn that a little better before you try to develop an emulator or it could become a nightmare trying to implement something you half understand with a code you don't know too well what it does.

In the other case.. you should head to information about your target console. How does it works? How many CPU does it have? Sound? GPU? Joypads? Etc.. You won't be emulating a console without all its information. That's where a new problem arises.. you usually can get superficial information about each part of the console, but getting the deep information you sometimes need is quite hard. Luckyly in my case.. the gameboy is well documented, though a couple of details are still missing or I just haven't seen them :)

My primary sources of information are:
http://marc.rawer.de/Gameboy/
http://nocash.emubase.de/pandocs.htm

Ok, ok.. I'm missing something here, I know. Thre are basic guidelines you can follow to develop an emulator. But it has been done by quite a lot of people and I couldn't do a better job at it so I'll just will give you a link.
http://web.archive.org/web/20050414012510/www.pj64.net/emubook/

There you'll get basic information about how a console works. Also.. there's a document by Victor Moya about emulators which is great and has lots of details.

On the next posts I will talk about how I implemented each of the parts that are explained on those documents and when finished the basic explanation I will start adding work logs in a more "technical" way.

Born of an Emulator

Well, first I have to say that I usually don't like to use blogs, but in this case I've made an exception because I think is right to share the knowledge one acquires.

In this blog, at least for now, I'm going to post about the process of creating an emulator. This should help all the people that, just like me, wants to get involved in this area.

I should say I don't have too much experience doing emulators so probably a lot of stuff could be done in a better way than how it's done. This is my first emulator I have started from scratch and because of this I haven't focused on optimizing anything. I know it probably would have been better to optimize while developing, specially for the CPU, since it's a lot of work that you will have to do again when optimizing, but I didn't want to get into that just yet.

The console I'm trying to emulate is a Monochrome GameBoy for now and I expect to make it emulate ColorGB and maybe SGB and PocketGB in the near future. This emulator don't have a name yet as I only have created it for fun and to learn how to program an emulator.

If you consider that I started developing this like two weeks ago and that I'm working full time as a summer student (I'm from Chile). I think the progress has been awesome!

When I started this emulator project I thought that a Blog about this would have helped me a lot, specially with those details that nobody informs you about! So that's why I'm creating it, to help others in similar situations. But before starting the Blog I wanted to make sure I could handle the emulator, so I can share knowledge and not just problems. So here is what has been done:

- CPU with Interruption Handling.
- Memory Handling and Memory Mapping.
- Video Handling (Still not showing the user screen but soon!).
- Showing in use Tile Data.
- Multithreaded Video and CPU synch (Not the fastest method, but I like to keep it real!).

Probably there are a couple of bugs in each of those sections, but I manage to see the tile data of some games changing through time :)

I started developing in linux, but I have changed it since I wanted to learn and use DirectX. So now I'm using Microsoft Visual Studio 2008 and the latest DirectX SDK, the one from November 2008. I'll try to do it as flexible as possible, so it's easy to change it to OpenGL, SDL or any other renderer's API, such as a handmade one.

Ok. That's about it. I'm sorry if I have bad English but it's just not my first language. I will try to post again in one or two days(or maybe sooner) to start unveiling the mysteries of emulating a console.

For now I have an image of DropZone tile data:


Haven't worked on the palettes, so that's why the colors are red, blue and green.