danieljon.es

index posts opinions portfolio

Posts

My posts about programming and things.
Date format is day/month/year because I'm sane.

CHIP-8 interpreter #1 - graphics

17/8/2020

I'm working on an implementation of a CHIP-8 interpreter using SDL2 for graphics and sound, in C. I plan to implement the interpreter in parts and have them accompanied with a website post.

What is CHIP-8

CHIP-8 is an interpreted programming language made in the mid 1970's to allow video games to be easier to create and portable for the incompatible systems of the time.

CHIP-8 specs:
Memory layout:

Graphics

The original CHIP-8 (and the one I'm implementing) uses a 64x32 pixel display. Originally, this would have been viewed on a television of the time, however today we have massive displays - this is just too small. So to fix that we need to implement some scaling, thankfully SDL2 handles this for us.

CHIP-8 graphics are drawn using sprites. A sprite is always 8 pixels wide and can be up to 15 pixels tall. Each pixel is a single bit, so each byte has 8 pixels inside it, this equates to a sprite 1 byte wide and up to 15 bytes tall.

As an example, the letter 'E' as a sprite:
"E"BinaryHex
****
*   
****
*   
****
11110000
10000000
11110000
10000000
11110000
0xF0
0x80
0xF0
0x80
0xF0
This sprite will be put into memory somewhere. We will write an instruction to draw a sprite at location x,y with a length of N bytes. The interpreter will draw N bytes at the location stored in the 'I' register at the requested coordinate.

Sprite pixels are not turned off and on as you'd expect, instead they're XOR'd. In my interpreter video memory is an array of 64x32 values. To draw a set pixel of a sprite, the index into video memory is XOR'd with 1 (or in my case 0xFFFFFF). This means if the bit was already turned on, it will be turned off - it's toggling the pixel. In the case of a pixel being turned off because of the XOR, the 0xF register is set to 1 to indicate to the program that a sprite collision has occurred.

If you don't understand the XOR operation see my post detailing how bitwise operations work.

CHIP-8 documentation states that a sprite should wrap around when it is drawn out of bounds. This is achieved with the modulo operator(Modulo is the remained when two numbers are divided, example: 11 modulo 4 = 3, because 11 divides by 4 (twice), with 3 remaining). CHIP-9 has 64x32 display, so imagine the following:

We want to draw a pixel at x coordinate 27. 27 % 32 = 27 - the coordinate stays the same. However, if we try draw a pixel at x coordinate 35 we'll find that 35 % 32 = 3. We've clamped the possible x coordinates to 32, the difference between 35 and 32 is 3, and that is our new X coordinate as it wraps around.

In my interpreter we're treating a 1d array as 2d, so we need to map onto the array (bit is the current bit we're writing, 0-7 for the range of a byte):
destination_in_video_memory = WIDTH*(starty%HEIGHT)+((startx%WIDTH)+bit)

This is the function as it currently stands that draws a sprite to the screen:
void
chip8_draw_sprite(int startx, int starty, uint16_t mem, uint8_t size)
{
	/*
	 * draw sprite located at loc of height size at startx,starty
	 */

	uint8_t byte = 0;
	uint8_t mask = 0x1;
	V[0xF] = 0; /* set collision register to 0 */
	for (uint8_t byteoffset = 0; byteoffset < size; byteoffset++)
	{
		/* loop through each byte from mem to mem+size */
		byte = memory[mem+byteoffset];
		int bit = 0;
		for (mask = 0x80; mask != 0; mask >>= 1)
		{
			if (byte & mask)
			{
				uint32_t pixel = WIDTH*(starty%HEIGHT)+((startx%WIDTH)+bit);
				if (video[pixel] != 0)
				{
					/* if the video bit is already set, we need to set the collision register */
					V[0xF] = 1;
				}
				video[pixel] ^= 0xFFFFFF;
			}
			bit++;
		}
		starty++;
	}
}
This is written only for testing purposes, when I get to implementing the CHIP-8 instructions it will be rewritten.

The general gist of the function is: Current state of my interpreter. All it does right now is emulate how the display works, XORing the pixels and wrapping sprites. You can see two sprites colliding (the third invader and the fourth invader lined up), an invader sprite wrapping from right to left and one wrapping from the bottom to the top:



More posts should follow eventually detailing the other components.

The source code can be found in my git repository.


RSS feed
FSF member

page generated 10/4/2023 using websitegenerator in C