Chip8 Emulator
It all started roughly a week and a half ago. I think I was playing some SNES on my computer with my SNES USB controller adapter and I thought that it would be cool to implement a console emulator on a microcontroller. Then I was like "Hmmm I've got this ARM dev board I haven't done anything with, I should use it." So I researched a couple NES emulator projects and decided that I should start with something a little more basic. So I just read up on CPU emulation in general and learned a lot.
An emulator performs the functions of a source computer on a target computer so that that target acts like the source. Basically you are simulating one computer on another one.
It helps to have some knowledge of the inner workings of a CPU when you are coding an emulator. In my Intro. to Mechatronics course last year, covered the hardware of the HC12 a lot since we were coding the chip in assembly. I got familiar with the various registers, accumulators, status bits, etc that the CPU consisted of. Pretty much any experience coding a microcontroller at the hardware level will help you to understand how emulators work.
Anyways the Chip8 is probably the easiest emulator to write. It only has 35 opcodes. The Chip8 itself is pretty interesting since it is actually just an interpreter that ran on old microcomputers. Wikipedia describes it pretty well. It has 4k of memory, 16 general purpose registers, a 16 level stack, and two timers.
At the heart of any CPU really is the fetch, decode and execute cycle. That is exactly what the main loop of the emulator does. It reads the opcode at the memory location pointed to by the program counter, then decodes that opcode and finally executes it. In my emulator the memory is just an array. The program counter is used as the index of the array to read that location. Once the opcode is read, it is decoded by a giant switch statement. That is the route that one usually takes in their first emulator project. There are other way of decoding the instructions such as arrays of function pointers and dynamic recompilation. The switch statement is the easiest. Once the instruction has been decoded then all thats left is for the instruction to be executed. The functions of the instructions have to be 'translated' into whatever language the emulator is being written in, in my case C. For example the opcode 0x6xnn, sets the register x to nn, where x is a 4 bit number and nn is a byte.
case 0x6000: /* set VX to nn */
v[(op&0x0f00)>>8] = (op&0x00ff); /* Lots of bit math */
pc += 2; /* don't forget to increment the program counter */
break;
Always remember to increment the program counter, unless it is a jump instruction. I was missing one increment and it was messing up everything. After all the instructions have been correctly translated then you should have a working emulator. In order for this to actually be of some use, I had to add a display so that I could play the games.
I wrote a simple graphics program using SDL, which is really easy to use. With absolutely no experience using the library or graphics in general, I had a display up really quick with no head aches. The SDL library also handles interfacing with the key board so that I can play games.
Here it is running Space Invaders.
Stuff in the works
- Super Chip instructions
- alternative opcode decoding(function pointers)
- debug info below screen(fps, opcode, pc, register values)
- reset and load game rom
- port to cygni dev board with tv out
Looks like the Gameboy is probably the next step up in emulator development. I'll try to tackle that one next. It's going to be a little more complicated than this.
Here are some resources for Chip8 Emulators
tutorial - http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/
tutorial - http://www.codeslinger.co.uk/pages/projects/chip8.html
Tech - http://devernay.free.fr/hacks/chip8/C8TECH10.HTM
An emulator performs the functions of a source computer on a target computer so that that target acts like the source. Basically you are simulating one computer on another one.
It helps to have some knowledge of the inner workings of a CPU when you are coding an emulator. In my Intro. to Mechatronics course last year, covered the hardware of the HC12 a lot since we were coding the chip in assembly. I got familiar with the various registers, accumulators, status bits, etc that the CPU consisted of. Pretty much any experience coding a microcontroller at the hardware level will help you to understand how emulators work.
Anyways the Chip8 is probably the easiest emulator to write. It only has 35 opcodes. The Chip8 itself is pretty interesting since it is actually just an interpreter that ran on old microcomputers. Wikipedia describes it pretty well. It has 4k of memory, 16 general purpose registers, a 16 level stack, and two timers.
At the heart of any CPU really is the fetch, decode and execute cycle. That is exactly what the main loop of the emulator does. It reads the opcode at the memory location pointed to by the program counter, then decodes that opcode and finally executes it. In my emulator the memory is just an array. The program counter is used as the index of the array to read that location. Once the opcode is read, it is decoded by a giant switch statement. That is the route that one usually takes in their first emulator project. There are other way of decoding the instructions such as arrays of function pointers and dynamic recompilation. The switch statement is the easiest. Once the instruction has been decoded then all thats left is for the instruction to be executed. The functions of the instructions have to be 'translated' into whatever language the emulator is being written in, in my case C. For example the opcode 0x6xnn, sets the register x to nn, where x is a 4 bit number and nn is a byte.
case 0x6000: /* set VX to nn */
v[(op&0x0f00)>>8] = (op&0x00ff); /* Lots of bit math */
pc += 2; /* don't forget to increment the program counter */
break;
Always remember to increment the program counter, unless it is a jump instruction. I was missing one increment and it was messing up everything. After all the instructions have been correctly translated then you should have a working emulator. In order for this to actually be of some use, I had to add a display so that I could play the games.
I wrote a simple graphics program using SDL, which is really easy to use. With absolutely no experience using the library or graphics in general, I had a display up really quick with no head aches. The SDL library also handles interfacing with the key board so that I can play games.
Here it is running Space Invaders.
Stuff in the works
- Super Chip instructions
- alternative opcode decoding(function pointers)
- debug info below screen(fps, opcode, pc, register values)
- reset and load game rom
- port to cygni dev board with tv out
Looks like the Gameboy is probably the next step up in emulator development. I'll try to tackle that one next. It's going to be a little more complicated than this.
Here are some resources for Chip8 Emulators
tutorial - http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/
tutorial - http://www.codeslinger.co.uk/pages/projects/chip8.html
Tech - http://devernay.free.fr/hacks/chip8/C8TECH10.HTM


1 comments:
Yeah, Even I tried to code one, I am ATM. Thanks for the 6xxx instruction and I wasn't shifting it 8 bits.
Post a Comment