In this post, I will describe how I render graphics in my emulators using OpenGL, although, the idea of drawing to textures applies to any modern graphics library.
I interface the Windows API and OpenGL to create a GUI that I can render graphics to. To render the graphics, I create a texture in the following way.
// create a texture
glTexImage2D(GL_TEXTURE_2D, 0, 3, x_res, y_res, 0, GL_RGB, GL_UNSIGNED_BYTE, screenData);
// set up the texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
and update the texture like this
// Update texture
glTexSubImage2D(GL_TEXTURE_2D, 0 ,0, 0, NTSC_WIDTH, NTSC_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, screenData);
The pixel buffer i use is a 3 dimensional array, which is layed out in the following way.
u8 screenData[y][x][3];
The last 3 being the RGB value for each pixel
So, lets say I wanted to draw a blue pixel at coords(X:10, Y:15), i would do something like this.
// Draw blue pixel
screenData[15][10][0] = 0; // R
screenData[15][10][1] = 0; // G
screenData[15][10][2] = 255; // B
I wont' explain too much more, instead, I'll provide the source to a small program I created to show you, which can be download from the following link. It can be compiled with Visual C++ 2010. This program creates a texture and draws some pixels to it, and also stretches the scene depending on the width and height of the window and creates a small menu, just for the sake of it.
Download here.
You will notice that in my DrawScene() function, I rotate and texture, this is because by default the bottom left is coord 0,0, when i want the top left to be 0,0.
If link goes down, make me aware please.
Peace
Tuesday, 31 August 2010
How emulators work
In this post, I'll attempt to explain how emulators fundamentally work.
The legalities
In general, writing an emulator is considered legal, as long as it's is all your work and all the documentation has been gathered legally, but spreading copyrighted work such as ROMs is highly illegal and I will not provide download links, so please, don't ask.
Different methods of emulating a system
The CPU of any system is pretty much the most important part, it is essentially the brain of the system, assuming the system doesn't have two or more brains (co processors), so your emulator will be based around the CPU core you write. To write a CPU emulator, you need to first understand how a CPU works. A CPU works on the basis of fetch, decode, execute.
- Fetch: Retrieve the instruction from memory.
- Decode: Figure out what the instruction is, this may be simple in an older 8 bit CPU.
- Execute: Execute the instruction and write back any resulting values etc...
- Interpreter
An interpreter is the most popular method of emulating chips such as CPU's inside systems. Here is the basic way that an interpreter works.
cyclesThisUpdate = 0;
while (cyclesThisUpdate < cyclesToExecute)
{
opcode = readMem(PC++); // fetch instruction
executeOpcode(opcode); // decode and execute instruction
// do cyclic tasks
doGraphics();
doSound();
checkInterupts();
}
Let me explain, "cyclesThisUpdate" is going to be the amount of cycles that the CPU has executed this update, usually we update the emulator one frame at a time then draw the screen. "cyclesThisUpdate" must be reset at the start of the loop. "cyclesToExecute" is simply the amount of cycles we want to execute for this update, for example, lets say we wanted to update about a frame, we would work out how many CPU cycles a frame takes to emulate. Be aware that "cyclesThisUpdate" will be incremented a certain amount by the instruction, certain instructions will take more cycles than others to execute, not including memory access times. You will need to keep track of these cycles.
As you can see, the first thing we do is fetch the instruction, we then decode and execute the instruction, after this, we do all the cyclic tasks that need to be emulated, such as video, sound and CPU interupts. Fetching the instruction involves memory I/O, which will need to be emulated. For example, your fetch step will probably be some kind of readMemory() function which takes an address as a parameter, and returns the data as that address. This will serve the purpose of figuring out where in memory you are trying to read, and acting appropriately. For example, in the Gameboy Classic, reading addresses 0x4000, to 0x7FFF is reading a memory bank, and you must perform ROM memory banking to return the correct bytes. The "PC" is the program counter, which keeps track of where we are in the program, instructions like branches and jumps will change this register and it is incremented past each instruction everytime one is executed. If this confuses you, don't worry, you will understand eventually.
TL:DR Emulator is updated until cycles per update (usually per frame) is achieved.
Benefits of interpretation
- Easy to debug
- Simple to implement
- Portable
- Easy to synchronise your system
Drawbacks of interpretation
- Very slow compared to other methods
- Dynamic Recompilation
Recompilation or Dynarec for short, is a complex subject that I'm not really fully qualified to explain. The theory is that instead of executing the instructions, you translate them into mechine code instructions for your system and cache them in code blocks. The idea behind this is for optimization, because most code that is executed might be executed thousands of times, so if it is cached and optimized, it will execute much faster. Here is a great tutorial by one of thr PCSX2 authors, CottonVibes on Dynarec.
Emulators like PCSX2, ePSXe, PJ64, 1964 and Dolphin use Dynamic Recompilation. You can freely download the PCSX2 source and the 1964 source and take a look at there recompilers, 1964 even has a pdf document floating around somewhere with details on there recompiler, ask me if you want it, ill upload it somewhere for you.
Benefits of dynarec
- Speed
- Speed
- Speed
Drawbacks of dynarec
- Not portable
- Difficult to debug
- Hard to impliment
There is another method called static recompilation, but I won't go into that as I feel that the benefits are few and far between.
Peace
By the way, i have no idea why this post won't format correctly, sorry. I tried.
Monday, 30 August 2010
A C++ wallpaper
After seeing the antiRTFM's C++ tutorials on youtube, I saw that he had an awesome wallpaper that he designed. People kept requesting it so I thought I'd make my own impression of it. Do what you will with it. Enjoy :)
Peace
Peace
Writing an emulator
In this quick post, I'll go over the processes that led up to me writing emulators.
*First of all, a disclaimer. I am not an expert, or even a particularly advanced emulator author, but I am learning more everyday and really enjoying it. If you want to speak to expert emulator authors, go to a site like PCSX2.net. These people deserve enormous respect in my humble opinion.
From the very first time I used an emulator, I knew that I wanted to learn more about them, I don't even think I was a programmer at that time, it was the interest that motivated me from the start. The reason I chose to actually attempt to write emulators is simple, I love playing games, and I love low level programming tasks and learning what makes machines "tick", emulation is ideal for me. Unfortunately, I noticed that learning the theory behind emulation is easier said than done, not to mention that lack of simple documentation on the basics which can be maddening. Emulating a games machine, or any machine is not a simple thing to do (in my opinion), although obviously writing a PS2 emulator is going to be alot harder than writing a Gameboy emulator for example, so it's subjective.
Here's a few suggestions.
Don't know how to program in C++? Here's a good tutorial.
Don't know how to program graphics and GUI in C++? Here's a good tutorial.
Take a look at this video before writing an emulator, it will help you understand what the basics are. (not sure about the copyright, but I tried to contact the author, no response). If the link goes down, please tell me, i will re-upload it for you.
Confident in your language of choice? This is an awesome blog taking you step by step through how to write an emulator. From the Chip8, to the Gameboy Classic, to the Master System, to infinity... and beyond!
A great site for emulator source code and such.
The NO$ series of emulators and documentation. (great, great documentation on various systems like the Gameboy Advanced, Nintendo DS and the NES etc...). this will probably be your main source of documentation for a few emulators.
And of course, if you want more documentation, don't be afraid to use the official documentation released by the system vendors (if they have of course). For example, the 6502 processor used in the NES has a whole manual. Same with the GBA CPU, the ARM7TDI manual.
One last thing, don't forget to actually play emulators, they are so much fun. try the latest ones, the PCSX2 and Dolphin, they be bitchin!
Peace
*First of all, a disclaimer. I am not an expert, or even a particularly advanced emulator author, but I am learning more everyday and really enjoying it. If you want to speak to expert emulator authors, go to a site like PCSX2.net. These people deserve enormous respect in my humble opinion.
From the very first time I used an emulator, I knew that I wanted to learn more about them, I don't even think I was a programmer at that time, it was the interest that motivated me from the start. The reason I chose to actually attempt to write emulators is simple, I love playing games, and I love low level programming tasks and learning what makes machines "tick", emulation is ideal for me. Unfortunately, I noticed that learning the theory behind emulation is easier said than done, not to mention that lack of simple documentation on the basics which can be maddening. Emulating a games machine, or any machine is not a simple thing to do (in my opinion), although obviously writing a PS2 emulator is going to be alot harder than writing a Gameboy emulator for example, so it's subjective.
Here's a few suggestions.
- First of all, you obviously need to learn a programming language, i recommend C and/or C++ as most software, including most emulators will be written in this language, even Windows is written almost entirely in C.
- Emulation is not really a good project for learning your language of choice, be confident in your language before you attempt writing any emulator, as you don't want to be discouraged from emulation by your lack of knowledge of a language, a language should be used like any other tool, which you should know how to make full use of before attempting projects like this. Although, I have heard of people saying that they learned to program by writing emulators, but I digress.
- Don't ever just copy somone elses source code because you can't figure it out yourself, this is a huge mistake and will ultimately screw you over, it feels so much better to know you have witten it all yourself.
- Learn about the system you're trying to emulate before writing any code.
- Learn about computer architecture before trying ti write an emulator.
- Learn about bitwise operators like OR, EOR and AND. Also, learn about different numeral systems like binary and hexadecimal.
- Find as much documentation as you can on the system you're trying to emulate.
- Don't give up.
- Have fun. :)
- ???
- Profit!
Don't know how to program in C++? Here's a good tutorial.
Don't know how to program graphics and GUI in C++? Here's a good tutorial.
Take a look at this video before writing an emulator, it will help you understand what the basics are. (not sure about the copyright, but I tried to contact the author, no response). If the link goes down, please tell me, i will re-upload it for you.
Confident in your language of choice? This is an awesome blog taking you step by step through how to write an emulator. From the Chip8, to the Gameboy Classic, to the Master System, to infinity... and beyond!
A great site for emulator source code and such.
The NO$ series of emulators and documentation. (great, great documentation on various systems like the Gameboy Advanced, Nintendo DS and the NES etc...). this will probably be your main source of documentation for a few emulators.
And of course, if you want more documentation, don't be afraid to use the official documentation released by the system vendors (if they have of course). For example, the 6502 processor used in the NES has a whole manual. Same with the GBA CPU, the ARM7TDI manual.
One last thing, don't forget to actually play emulators, they are so much fun. try the latest ones, the PCSX2 and Dolphin, they be bitchin!
Peace
Friday, 27 August 2010
Decoding the THUMB instruction set
Recently, I have began work on a GBA emulator which is keeping me busy. The emulator that I worked on before this (and still do) is a Nes emulator, so this is a huge step up for me, but where is the fun without challenge?
So far, i haven't even finished decoding the instruction sets so don't expect much yet, the ARM7TDMI is a pretty complex CPU. I will outline the method that I am using to decode the instruction sets of the ARM7TDMI, incase it's useful to any other GBA emulator authors who were stuck like I was blankly staring at the ARM7 opcode format for ages.
Keep in mind that it is very difficult to explain the exact way that i decode each instruction without alot of text, but I will try to explain as best I can with some abstraction.
Each instruction is made up of 2 bytes (half word), and each instruction has it's own format that is decoded by the CPU. As you can see, some instruction formats like format 1 have an opcode field which will specify the particular instruction that this is, for example, the "Move shifted register" format has a 2 bit opcode field. If you want more detail on the specifics of the instructions and the fields, then take a look at the manual here, or check out NO$GBA specs here.
Now, the way I decode an instruction is by taking the upper 8 bits of the instruction and checking it's value. For example, if I took the upper 8 bits and the value was equal to 0 to 7, I would know that this must be a "LSL Rd, Rs, Offset". Why? This is because while the upper 8 bits equal 0 to 7, then the opcode field (move shifted register format) is equal to 0 and all the other bits for this format are correct. here is a more visual example.
Let's say our upper 8 bits look like the ones in the picture
00000101
If we check the instruction format, we can see that the "Move shifted register" format allows for this value, as the bottom three bits of 8 bit value we are using are the top three bits of the offset5 field (bits 8,9, 10), which could therefor be anything as they are arbitrary, so the following binary values can therefor reperesent the same instruction. ("LSL Rd, Rs, Offset5").
00000000 (0)
00000001 (1)
00000010 (2)
00000011 (3)
00000100 (4)
00000101 (5)
00000110 (6)
00000111 (7)
If we were to get a value of 8 (00001000), this would mean that the opcode field had increased by one, so the instruction would now be "LSR Rd, Rs, Offset5". So now, we need to do the same again, as the bottom three bits could be anything. these binary values will all be the same instruction.
00001000 (8)
00001001 (9)
00001010 (A)
00001011 (B)
00001100 (C)
00001101 (D)
00001110 (E)
00001111 (F)
Now to decode the rest of the instruction set, you just follow this logical pattern.
Here is a coded example of how you might decode the first couple of instructions...
<textarea>u16 instruction = fetch();
switch (instruction >> 8)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
{
// LSL Rd, Rs, Offset5
} break;
case 8:
case 9:
case 0xA:
case 0xB:
case 0xC:
case 0xD:
case 0xE:
case 0xF:
{
// LSR Rd, Rs, Offset5
} break;
}
or you may choose to use an array of function pointers.
void (*CPU_Thumb_Instruction[0x100]) (u16 instruction) =
{
Thumb_LSL_Rd_Rs_Offset, // 00h
Thumb_LSL_Rd_Rs_Offset, // 01h
Thumb_LSL_Rd_Rs_Offset, // 02h
Thumb_LSL_Rd_Rs_Offset, // 03h
Thumb_LSL_Rd_Rs_Offset, // 04h
Thumb_LSL_Rd_Rs_Offset, // 05h
Thumb_LSL_Rd_Rs_Offset, // 06h
Thumb_LSL_Rd_Rs_Offset, // 07h
/*-------------------*/
Thumb_LSR_Rd_Rs_Offset, // 08h
Thumb_LSR_Rd_Rs_Offset, // 09h
Thumb_LSR_Rd_Rs_Offset, // 0Ah
Thumb_LSR_Rd_Rs_Offset, // 0Bh
Thumb_LSR_Rd_Rs_Offset, // 0Ch
Thumb_LSR_Rd_Rs_Offset, // 0Dh
Thumb_LSR_Rd_Rs_Offset, // 0Eh
Thumb_LSR_Rd_Rs_Offset, // 0Fh
};
</textarea>
I will explain how to decode the ARM instruction set at a later date, as it is considerably more complex, and requires much more thought and care.
Peace
So far, i haven't even finished decoding the instruction sets so don't expect much yet, the ARM7TDMI is a pretty complex CPU. I will outline the method that I am using to decode the instruction sets of the ARM7TDMI, incase it's useful to any other GBA emulator authors who were stuck like I was blankly staring at the ARM7 opcode format for ages.
Keep in mind that it is very difficult to explain the exact way that i decode each instruction without alot of text, but I will try to explain as best I can with some abstraction.
The ARM7TDMI effectively has two instruction sets, one that makes use of full 32bit instructions called the ARM instruction set, and another which only uses 16 bit instructions called the THUMB instruction set which reduces code density but removes some instructions as well as limiting the immediate values that can be used. You can independently switch between these two instruction sets on the fly using the BX instruction.
THUMB instruction set
As the THUMB instruction set is the easiest to decode, I will tackle this first.
Binary opcode format of the THUMB instruction set.
Each instruction is made up of 2 bytes (half word), and each instruction has it's own format that is decoded by the CPU. As you can see, some instruction formats like format 1 have an opcode field which will specify the particular instruction that this is, for example, the "Move shifted register" format has a 2 bit opcode field. If you want more detail on the specifics of the instructions and the fields, then take a look at the manual here, or check out NO$GBA specs here.
Now, the way I decode an instruction is by taking the upper 8 bits of the instruction and checking it's value. For example, if I took the upper 8 bits and the value was equal to 0 to 7, I would know that this must be a "LSL Rd, Rs, Offset". Why? This is because while the upper 8 bits equal 0 to 7, then the opcode field (move shifted register format) is equal to 0 and all the other bits for this format are correct. here is a more visual example.
Let's say our upper 8 bits look like the ones in the picture
00000101
If we check the instruction format, we can see that the "Move shifted register" format allows for this value, as the bottom three bits of 8 bit value we are using are the top three bits of the offset5 field (bits 8,9, 10), which could therefor be anything as they are arbitrary, so the following binary values can therefor reperesent the same instruction. ("LSL Rd, Rs, Offset5").
00000000 (0)
00000001 (1)
00000010 (2)
00000011 (3)
00000100 (4)
00000101 (5)
00000110 (6)
00000111 (7)
If we were to get a value of 8 (00001000), this would mean that the opcode field had increased by one, so the instruction would now be "LSR Rd, Rs, Offset5". So now, we need to do the same again, as the bottom three bits could be anything. these binary values will all be the same instruction.
00001000 (8)
00001001 (9)
00001010 (A)
00001011 (B)
00001100 (C)
00001101 (D)
00001110 (E)
00001111 (F)
Now to decode the rest of the instruction set, you just follow this logical pattern.
Here is a coded example of how you might decode the first couple of instructions...
<textarea>u16 instruction = fetch();
switch (instruction >> 8)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
{
// LSL Rd, Rs, Offset5
} break;
case 8:
case 9:
case 0xA:
case 0xB:
case 0xC:
case 0xD:
case 0xE:
case 0xF:
{
// LSR Rd, Rs, Offset5
} break;
}
or you may choose to use an array of function pointers.
void (*CPU_Thumb_Instruction[0x100]) (u16 instruction) =
{
Thumb_LSL_Rd_Rs_Offset, // 00h
Thumb_LSL_Rd_Rs_Offset, // 01h
Thumb_LSL_Rd_Rs_Offset, // 02h
Thumb_LSL_Rd_Rs_Offset, // 03h
Thumb_LSL_Rd_Rs_Offset, // 04h
Thumb_LSL_Rd_Rs_Offset, // 05h
Thumb_LSL_Rd_Rs_Offset, // 06h
Thumb_LSL_Rd_Rs_Offset, // 07h
/*-------------------*/
Thumb_LSR_Rd_Rs_Offset, // 08h
Thumb_LSR_Rd_Rs_Offset, // 09h
Thumb_LSR_Rd_Rs_Offset, // 0Ah
Thumb_LSR_Rd_Rs_Offset, // 0Bh
Thumb_LSR_Rd_Rs_Offset, // 0Ch
Thumb_LSR_Rd_Rs_Offset, // 0Dh
Thumb_LSR_Rd_Rs_Offset, // 0Eh
Thumb_LSR_Rd_Rs_Offset, // 0Fh
};
</textarea>
I will explain how to decode the ARM instruction set at a later date, as it is considerably more complex, and requires much more thought and care.
Peace
Welcome
Hi, this is a blog I thought I'd start just to note my progress and thoughts of various coding projects I am working on. Nuff said, let's do this.
Subscribe to:
Posts (Atom)