codeslinger.co.uk

The chip8 hardware emulation.

Hardware:

So reading the wikipedia entry for chip8 we know that the chip8 system is made of the following:

The graphics hardware is discussed at the bottom of this page and sound and timers etc is handled in another area of the site (step 4 of the navigation bar to your right).

Hardware Emulation:

So to emulate the chip8 we need variables of sizes 8-bit (1 byte) and 16-bits(2 bytes, or 1 word). A type char is 1 byte long and short int is 1 word long which will give us the following typedefs:

typedef unsigned char BYTE;
typedef unsigned short int WORD;

We need them to be unsigned so we can hold values of 0 to 255 (for BYTE) instead of -127 to +127. The same goes for the WORD 0 - 65535.

We know from our hardware specification that the following variables is what we need to emulate the chip8 hardware:

BYTE m_GameMemory[0xFFF] ; // 0xFFF bytes of memory
BYTE m_Registers[16] ; // 16 registers, 1 byte each
WORD m_AddressI ; // the 16-bit address register I
WORD m_ProgramCounter ; // the 16-bit program counter
std::vector m_Stack; // the 16-bit stack

To really emulate the chip8 there is a stack pointer which points to memory which is used for the subroutine return calls. However this can be just as easily emulated with a vector for return addresses that you can just push and pop variables onto.

Now we have our hardware variables it is time to initialize them. Wikipedia says that the game is loaded into memory 0x200 as 0-1FFF is for the interpreter. So all we need to do is load the game into 0x200 and initialize the other variables. Remember that the program counter is the variable used to point to which part of memory we are currently executing so this needs to be set to the first instruction of the game which will be address 0x200

void CPUReset( )
{
   m_AddressI = 0 ;
   m_ProgramCounter = 0x200 ;
   memset(m_Registers,0,sizeof(m_Registers)) ; // set registers to 0

   // load in the game
   FILE *in;
   in = fopen( "c:/INVADERS", "rb" );
   fread( &m_GameMemory[0x200], 0xfff, 1, in);
   fclose(in);
}

And thats all there is to it, pretty easy so far, it doesnt get much more difficult.

Graphic Emulation:

The graphics work by drawing sprites at a specific X and Y position on screen. The X and Y coordinates refer to the top left pixel of the sprite. Every sprite has a width of 8 pixels and a variable height. Sprite data is stored in game memory at the address the I register points to. Each byte of this memory represents 1 line of the sprite to draw. As just stated each line is always 8 pixels wide meaning that each pixel can be represented by 1 bit in the byte. If the bit for the pixel is set to 0 it means ignore this pixel leaving it at its current state. If the bit is set to 1 then it means toggle the state of the pixel (if it is currently on then set it to off otherwise set it to on). If the pixel is toggled from on to off then the flag register gets set to 1 otherwise it will be set to 0. This will represent a collision in sprites. Opcode DXYN is responsible for the graphic drawings. The resolution of the display is 64x32 and can be represented in the emulator as a 2D array.

BYTE m_ScreenData[64][32] ;

Of course a resolution of 64x32 is pretty small so you can scale it however you like when you actually come to drawing the screen data. This is enough information to emulate the chip8 graphics however feel free to head over to David Winters site for a more indepth look at the chip8 graphics. The implementation of the opcode DXYN is discussed in the Example Opcode section of this site. You can use the navigation bar to your right to move on the next step, the fetch and decode loop