commit ec41dcbf9e85f1ab6c4859fbf3e07f0887e6686f
parent 00f98716353245d5e15772e08de47a397a581423
Author: Christos Margiolis <christos@margiolis.net>
Date: Mon, 19 Oct 2020 04:47:33 +0300
improved style, made indentation 8 spaces
Diffstat:
M | LICENSE | | | 0 | |
M | Makefile | | | 61 | +++++++++++++++++++++++++++++++++++-------------------------- |
M | README.md | | | 1 | - |
M | chip8.c | | | 579 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
4 files changed, 333 insertions(+), 308 deletions(-)
diff --git a/LICENSE b/LICENSE
diff --git a/Makefile b/Makefile
@@ -1,20 +1,22 @@
+# See LICENSE file for copyright and license details.
+
BIN = chip8
VERSION = 0.1
DIST = ${BIN}-${VERSION}
MAN1 = ${BIN}.1
PREFIX = /usr/local
MAN_DIR = ${PREFIX}/man/man1
-BIN_DIR = ${PREFIX}bin
+BIN_DIR = ${PREFIX}/bin
EXT = c
SRC = ${wildcard *.${EXT}}
OBJ = ${SRC:%.${EXT}=%.o}
CC = gcc
-CPPFLAGS += -Iinclude -DVERSION=\"${VERSION}\"
-CFLAGS += -Wall -std=c99 -pedantic -O3
-LDFLAGS += -Llib
-LDLIBS += -lSDL2
+INCS = -Iinclude
+CPPFLAGS = -DVERSION=\"${VERSION}\"
+CFLAGS = -Wall -std=c99 -pedantic -O3 ${INCS} ${CPPFLAGS}
+LDFLAGS = -Llib -lSDL2
CP = cp -f
RM = rm -f
@@ -23,37 +25,44 @@ MKDIR = mkdir -p
TAR = tar -cf
GZIP = gzip
-all: ${BIN}
+all: options ${BIN}
+
+options:
+ @echo ${BIN} build options:
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "LDFLAGS = ${LDFLAGS}"
+ @echo "CC = ${CC}"
${BIN}: ${OBJ}
- ${CC} ${LDFLAGS} $^ ${LDLIBS} -o $@
+ ${CC} ${LDFLAGS} $^ -o $@
-%.o: %.${EXT}
- ${CC} ${CPPFLAGS} ${CFLAGS} -c $< -o $@
+${OBJ}: ${SRC}
+ ${CC} ${CFLAGS} -c $< -o $@
dist: clean
- ${MKDIR} ${DIST}
- ${CP} -R roms ${SRC} LICENSE Makefile README.md ${DIST}
- ${TAR} ${DIST}.tar ${DIST}
- ${GZIP} ${DIST}.tar
- ${RM_DIR} ${DIST}
+ ${MKDIR} ${DIST}
+ ${CP} -R roms ${SRC} LICENSE Makefile README.md ${DIST}
+ ${TAR} ${DIST}.tar ${DIST}
+ ${GZIP} ${DIST}.tar
+ ${RM_DIR} ${DIST}
run:
- ./${BIN}
+ ./${BIN}
install: all
- ${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR}
- ${CP} ${BIN} ${BIN_DIR}
- ${CP} ${MAN1} ${DESTDIR}${MAN_DIR}
- sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1}
- chmod 644 ${DESTDIR}${BIN_DIR}/${BIN}
- chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1}
+ #${MKDIR} ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN_DIR}
+ ${MKDIR} ${DESTDIR}${BIN_DIR}
+ ${CP} ${BIN} ${BIN_DIR}
+ #${CP} ${MAN1} ${DESTDIR}${MAN_DIR}
+ #sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MAN_DIR}/${MAN1}
+ chmod 755 ${DESTDIR}${BIN_DIR}/${BIN}
+ #chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1}
-uninstall: all
- ${RM} ${DESTDIR}${BIN_DIR}/${BIN}
- ${RM} ${DESTDIR}${MAN_DIR}/${MAN1}
+uninstall:
+ ${RM} ${DESTDIR}${BIN_DIR}/${BIN}
+ #${RM} ${DESTDIR}${MAN_DIR}/${MAN1}
clean:
- ${RM} ${OBJ} ${BIN}
+ ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz
-.PHONY: all clean dist install uninstall run
+.PHONY: all options clean dist install uninstall run
diff --git a/README.md b/README.md
@@ -17,7 +17,6 @@ $ ./chip8 [../path/to/ROM]
In order to install do
```shell
$ cd path/to/chip8
-$ make
$ sudo make install
$ make clean # optional
```
diff --git a/chip8.c b/chip8.c
@@ -1,10 +1,13 @@
-#define _DEFAULT_SOURCE
+/* See LICENSE file for copyright and license details. */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
+
#include <SDL2/SDL.h>
+
#ifdef _WIN_32
typedef unsigned int uint32_t
typedef unsigned short uint16_t
@@ -17,25 +20,25 @@ typedef unsigned char uint8_t
#define FALSE 0
struct Chip8 {
- uint16_t I;
- uint16_t opcode;
- uint16_t pc;
- uint16_t sp;
- uint16_t stack[16];
- uint8_t delaytimer;
- uint8_t drawflag;
- uint8_t gfx[64 * 32];
- uint8_t keys[16];
- uint8_t memory[4096];
- uint8_t soundtimer;
- uint8_t V[16];
+ uint16_t I;
+ uint16_t opcode;
+ uint16_t pc;
+ uint16_t sp;
+ uint16_t stack[16];
+ uint8_t delaytimer;
+ uint8_t drawflag;
+ uint8_t gfx[64 * 32];
+ uint8_t keys[16];
+ uint8_t memory[4096];
+ uint8_t soundtimer;
+ uint8_t V[16];
};
static const uint8_t keymap[16] = {
- SDLK_1, SDLK_2, SDLK_3, SDLK_4,
- SDLK_q, SDLK_w, SDLK_e, SDLK_r,
- SDLK_a, SDLK_s, SDLK_d, SDLK_f,
- SDLK_z, SDLK_x, SDLK_c, SDLK_v
+ SDLK_1, SDLK_2, SDLK_3, SDLK_4,
+ SDLK_q, SDLK_w, SDLK_e, SDLK_r,
+ SDLK_a, SDLK_s, SDLK_d, SDLK_f,
+ SDLK_z, SDLK_x, SDLK_c, SDLK_v
};
static void chip8_init(struct Chip8 *);
@@ -62,279 +65,289 @@ static void render(SDL_Renderer *, SDL_Texture *, struct Chip8 *);
void
chip8_init(struct Chip8 *chip8)
{
- uint8_t fontset[80] = {
- 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
- 0x20, 0x60, 0x20, 0x20, 0x70, // 1
- 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
- 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
- 0x90, 0x90, 0xF0, 0x10, 0x10, // 4
- 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
- 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
- 0xF0, 0x10, 0x20, 0x40, 0x40, // 7
- 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
- 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
- 0xF0, 0x90, 0xF0, 0x90, 0x90, // A
- 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
- 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
- 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
- 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
- 0xF0, 0x80, 0xF0, 0x80, 0x80 // F
- };
- pc = 0x200;
- opcode = 0;
- I = 0;
- sp = 0;
- delaytimer = 0;
- soundtimer = 0;
- memset(V, 0, 16 * sizeof(uint8_t));
- memset(keys, 0, 16 * sizeof(uint8_t));
- memset(stack, 0, 16 * sizeof(uint16_t));
- memset(gfx, 0, 2048 * sizeof(uint8_t));
- memset(memory, 0, 4096 * sizeof(uint8_t));
- int i;
- for (i = 0; i < 80; memory[i] = fontset[i], i++);
+ int i;
+ uint8_t fontset[80] = {
+ 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
+ 0x20, 0x60, 0x20, 0x20, 0x70, // 1
+ 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
+ 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
+ 0x90, 0x90, 0xF0, 0x10, 0x10, // 4
+ 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
+ 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
+ 0xF0, 0x10, 0x20, 0x40, 0x40, // 7
+ 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
+ 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
+ 0xF0, 0x90, 0xF0, 0x90, 0x90, // A
+ 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
+ 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
+ 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
+ 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
+ 0xF0, 0x80, 0xF0, 0x80, 0x80 // F
+ };
+ pc = 0x200;
+ opcode = 0;
+ I = 0;
+ sp = 0;
+ delaytimer = 0;
+ soundtimer = 0;
+ memset(V, 0, 16 * sizeof(uint8_t));
+ memset(keys, 0, 16 * sizeof(uint8_t));
+ memset(stack, 0, 16 * sizeof(uint16_t));
+ memset(gfx, 0, 2048 * sizeof(uint8_t));
+ memset(memory, 0, 4096 * sizeof(uint8_t));
+ for (i = 0; i < 80; memory[i] = fontset[i], i++)
+ ;
}
int
romload(struct Chip8 *chip8, const char *fpath)
{
- FILE *rom = fopen(fpath, "rb");
- if (rom == NULL) {
- fprintf(stderr, "Error loading ROM (%s). Exiting. . .\n", fpath);
- return FALSE;
- }
- fseek(rom, 0, SEEK_END);
- long romsize = ftell(rom);
- rewind(rom);
+ FILE *rom;
+ long romsize;
+ size_t res;
+ int i;
+ char *buf;
- char *buf;
- if ((buf = (char *)malloc(romsize * sizeof(char))) == NULL) {
- fprintf(stderr, "Cannot allocate memory. Exiting. . .\n");
- return FALSE;
- }
+ if ((rom = fopen(fpath, "rb")) == NULL) {
+ fprintf(stderr, "Error loading ROM (%s). Exiting. . .\n", fpath);
+ return FALSE;
+ }
+ fseek(rom, 0, SEEK_END);
+ romsize = ftell(rom);
+ rewind(rom);
- size_t res;
- if ((res = fread(buf, sizeof(char), (size_t)romsize, rom)) != romsize) {
- fprintf(stderr, "Error reading ROM. Exiting. . .\n");
- return FALSE;
- }
+ if ((buf = (char *)malloc(romsize * sizeof(char))) == NULL) {
+ fputs("Cannot allocate memory. Exiting. . .\n", stderr);
+ return FALSE;
+ }
- int i;
- if ((4096 - 512) > romsize)
- for (i = 0; i < romsize; i++)
- memory[i + 512] = (uint8_t)buf[i];
- else {
- fputs("ROM can't fit into memory. Exiting. . .\n", stderr);
- return FALSE;
- }
+ if ((res = fread(buf, sizeof(char), (size_t)romsize, rom)) != romsize) {
+ fputs("Error reading ROM. Exiting. . .\n", stderr);
+ return FALSE;
+ }
+
+ if ((4096 - 512) > romsize)
+ for (i = 0; i < romsize; i++)
+ memory[i + 512] = (uint8_t)buf[i];
+ else {
+ fputs("ROM can't fit into memory. Exiting. . .\n", stderr);
+ return FALSE;
+ }
- fclose(rom);
- free(buf);
- return TRUE;
+ fclose(rom);
+ free(buf);
+ return TRUE;
}
void
emulate(struct Chip8 *chip8)
{
- opcode = memory[pc] << 8 | memory[pc + 1]; // fetch
- if (decode(chip8)) {
- pc += 2; // execute
- timers_update(chip8);
- }
- printf("Opcode: %x\tMemory: %x\tI: %x\tSP: %x\tPC: %d\n",
- opcode, memory[pc] << 8 | memory[pc + 1], I, sp, pc);
+ opcode = memory[pc] << 8 | memory[pc + 1]; // fetch
+ if (decode(chip8)) {
+ pc += 2; // execute
+ timers_update(chip8);
+ }
+ printf("Opcode: %x\tMemory: %x\tI: %x\tSP: %x\tPC: %d\n",
+ opcode, memory[pc] << 8 | memory[pc + 1], I, sp, pc);
}
int
decode(struct Chip8 *chip8)
{
- switch (opcode & 0xF000) {
int i;
+
+ switch (opcode & 0xF000) {
case 0x0000: // 00E_
- switch (opcode & 0x00FF) {
+ switch (opcode & 0x00FF) {
case 0xE0: // 00E0 - Clear screen
- memset(gfx, 0, 2048 * sizeof(uint8_t));
- drawflag = TRUE;
- break;
+ memset(gfx, 0, 2048 * sizeof(uint8_t));
+ drawflag = TRUE;
+ break;
case 0xEE: // 00EE - Return from subroutine
- pc = stack[--sp];
- break;
+ pc = stack[--sp];
+ break;
default:
- fprintf(stderr, "Unknown opcode: %x\n", opcode);
- return FALSE;
- }
- break;
+ fprintf(stderr, "Unknown opcode: %x\n", opcode);
+ return FALSE;
+ }
+ break;
case 0x1000: // 1NNN - Jump to address NNN
- pc = (opcode & 0x0FFF) - 2;
- break;
+ pc = (opcode & 0x0FFF) - 2;
+ break;
case 0x2000: // 2NNN - Call subroutine at NNN
- stack[sp++] = pc;
- pc = (opcode & 0x0FFF) - 2;
+ stack[sp++] = pc;
+ pc = (opcode & 0x0FFF) - 2;
case 0x3000: // 3NNN - Skip next instruction if VX == NN
- if (V[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF)) pc += 2;
- break;
+ if (V[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF))
+ pc += 2;
+ break;
case 0x4000: // 4NNN - Skip next instruction if VX != NN
- if (V[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF)) pc += 2;
- break;
+ if (V[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF))
+ pc += 2;
+ break;
case 0x5000: // 5XY0 - Skip next instruction if VX == VY
- if (V[(opcode & 0x0F00) >> 8] == V[(opcode & 0x00F0) >> 4]) pc += 2;
- break;
+ if (V[(opcode & 0x0F00) >> 8] == V[(opcode & 0x00F0) >> 4])
+ pc += 2;
+ break;
case 0x6000: // 6XNN - Set VX to NN
- V[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
- break;
+ V[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
+ break;
case 0x7000: // 7XNN - Add NN to VX
- V[(opcode & 0x0F00) >> 8] += opcode & 0x00FF;
- break;
+ V[(opcode & 0x0F00) >> 8] += opcode & 0x00FF;
+ break;
case 0x8000: // 8XY_
- switch (opcode & 0x000F) {
+ switch (opcode & 0x000F) {
case 0x0000: // 8XY0 - Set VX to VY
- V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4];
- break;
+ V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4];
+ break;
case 0x0001: // 8XY1 - Set VX to (VX OR VY)
- V[(opcode & 0x0F00) >> 8] |= V[(opcode & 0x00F0) >> 4];
- break;
+ V[(opcode & 0x0F00) >> 8] |= V[(opcode & 0x00F0) >> 4];
+ break;
case 0x0002: // 8XY2 - Set VX to (VX AND VY)
- V[(opcode & 0x0F00) >> 8] &= V[(opcode & 0x00F0) >> 4];
- break;
+ V[(opcode & 0x0F00) >> 8] &= V[(opcode & 0x00F0) >> 4];
+ break;
case 0x0003: // 8XY3 - Set VX to (VX XOR VY)
- V[(opcode & 0x0F00) >> 8] ^= V[(opcode & 0x00F0) >> 4];
- break;
+ V[(opcode & 0x0F00) >> 8] ^= V[(opcode & 0x00F0) >> 4];
+ break;
case 0x0004: // 8XY4 - Add VY to VX, VF = 1 if there is a carry
- V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
- V[0xF] = (V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])) ? 1 : 0;
- break;
+ V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
+ V[0xF] = (V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])) ? 1 : 0;
+ break;
case 0x0005: // 8XY5 - Sub VY from VX, VF = 0 if there is a borrow
- V[0xF] = (V[(opcode & 0x00F0) >> 4] > V[(opcode & 0x0F00) >> 8]) ? 0 : 1;
- V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
- break;
+ V[0xF] = (V[(opcode & 0x00F0) >> 4] > V[(opcode & 0x0F00) >> 8]) ? 0 : 1;
+ V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
+ break;
case 0x0006: // 8XY6 - Shift VX right by 1. VF = LSB of VX before shift
- V[0xF] = V[(opcode & 0x0F00) >> 8] & 0x1;
- V[(opcode & 0x0F00) >> 8] >>= 1;
- break;
+ V[0xF] = V[(opcode & 0x0F00) >> 8] & 0x1;
+ V[(opcode & 0x0F00) >> 8] >>= 1;
+ break;
case 0x0007: // 8XY7 - Set VX to VY-VX. VF = 0 if there is a borrow
- V[0xF] = (V[(opcode & 0x0F00) >> 8] > V[(opcode & 0x00F0) >> 4]) ? 0 : 1;
- V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4] - V[(opcode & 0x0F00) >> 8];
- break;
+ V[0xF] = (V[(opcode & 0x0F00) >> 8] > V[(opcode & 0x00F0) >> 4]) ? 0 : 1;
+ V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4] - V[(opcode & 0x0F00) >> 8];
+ break;
case 0x000E: // 8XYE - Shift VX left by 1. VF = MSB of VX before shift
- V[0xF] = V[(opcode & 0x0F00) >> 8] >> 7;
- V[(opcode & 0x0F00) >> 8] <<= 1;
- break;
+ V[0xF] = V[(opcode & 0x0F00) >> 8] >> 7;
+ V[(opcode & 0x0F00) >> 8] <<= 1;
+ break;
default:
- fprintf(stderr, "Unknown opcode: %x\n", opcode);
- return FALSE;
- }
- break;
+ fprintf(stderr, "Unknown opcode: %x\n", opcode);
+ return FALSE;
+ }
+ break;
case 0x9000: // 9XY0 - Skip next instruction if VX != VY
- if (V[(opcode & 0x0F00) >> 8] != V[(opcode & 0x00F0) >> 4]) pc += 2;
- break;
+ if (V[(opcode & 0x0F00) >> 8] != V[(opcode & 0x00F0) >> 4])
+ pc += 2;
+ break;
case 0xA000: // ANNN - Set I to the address NNN
- I = opcode & 0x0FFF;
- break;
+ I = opcode & 0x0FFF;
+ break;
case 0xB000: // BNNN - Jump to NNN + V0
- pc = ((opcode & 0x0FFF) + V[0]) - 2;
- break;
+ pc = ((opcode & 0x0FFF) + V[0]) - 2;
+ break;
case 0xC000: // CNNN - Set VX to random number masked by NN
- V[(opcode & 0x0F00) >> 8] = (rand() % (0xFF + 1)) & (opcode & 0x00FF);
- break;
- case 0xD000: // Draw an 8 pixel sprite at (VX, VY)
- {
- uint16_t h = opcode & 0x000F;
- uint16_t pixel;
- uint8_t VX = V[(opcode & 0x0F00) >> 8];
- uint8_t VY = V[(opcode & 0x00F0) >> 4];
+ V[(opcode & 0x0F00) >> 8] = (rand() % (0xFF + 1)) & (opcode & 0x00FF);
+ break;
+ case 0xD000: { // Draw an 8 pixel sprite at (VX, VY)
+ int yl, xl;
+ uint16_t h = opcode & 0x000F;
+ uint16_t pixel;
+ uint8_t VX = V[(opcode & 0x0F00) >> 8];
+ uint8_t VY = V[(opcode & 0x00F0) >> 4];
- V[0xF] = 0;
- int yl, xl;
- for (yl = 0; yl < h; yl++) {
- pixel = memory[I + yl];
- for (xl = 0; xl < 8; xl++) {
- if ((pixel & (0x80 >> xl)) != 0) {
- if (gfx[VX + xl + ((VY + yl) * 64)] == 1)
- V[0xF] = 1;
- gfx[VX + xl + ((VY + yl) * 64)] ^= 1;
- }
+ V[0xF] = 0;
+ for (yl = 0; yl < h; yl++) {
+ pixel = memory[I + yl];
+ for (xl = 0; xl < 8; xl++) {
+ if ((pixel & (0x80 >> xl)) != 0) {
+ if (gfx[VX + xl + ((VY + yl) * 64)] == 1)
+ V[0xF] = 1;
+ gfx[VX + xl + ((VY + yl) * 64)] ^= 1;
+ }
+ }
}
- }
- drawflag = TRUE;
+ drawflag = TRUE;
}
- break;
+ break;
case 0xE000: // EX__
- switch (opcode & 0x00FF) {
+ switch (opcode & 0x00FF) {
case 0x009E: // EX9E - Skip next instruction if key in VX is pressed
- if (keys[V[(opcode & 0x0F00) >> 8]]) pc += 2;
- break;
+ if (keys[V[(opcode & 0x0F00) >> 8]])
+ pc += 2;
+ break;
case 0x00A1: // EXA1 - Skip next instruction if key in VX isn't pressed
- if (!keys[V[(opcode & 0x0F00) >> 8]]) pc += 2;
- break;
+ if (!keys[V[(opcode & 0x0F00) >> 8]])
+ pc += 2;
+ break;
default:
- fprintf(stderr, "Unknown opcode: %x\n", opcode);
- return FALSE;
- }
- break;
+ fprintf(stderr, "Unknown opcode: %x\n", opcode);
+ return FALSE;
+ }
+ break;
case 0xF000: // FX__
- switch (opcode & 0x00FF) {
+ switch (opcode & 0x00FF) {
case 0x0007: // FX07 - Set VX to delaytimer
- V[(opcode & 0x0F00) >> 8] = delaytimer;
- break;
- case 0x000A: // FX0A - Wait for key press and then store it in VX
- {
- int keypressed = FALSE;
- for (i = 0; i < 16; i++) {
- if (keys[i]) {
- V[(opcode & 0x0F00) >> 8] = i;
- keypressed = TRUE;
+ V[(opcode & 0x0F00) >> 8] = delaytimer;
+ break;
+ case 0x000A: { // FX0A - Wait for key press and then store it in VX
+ int keypressed = FALSE;
+
+ for (i = 0; i < 16; i++) {
+ if (keys[i]) {
+ V[(opcode & 0x0F00) >> 8] = i;
+ keypressed = TRUE;
+ }
}
- }
- if (!keypressed) return FALSE;
+ if (!keypressed)
+ return FALSE;
}
- break;
+ break;
case 0x0015: // FX15 - Set the delaytimer to VX
- delaytimer = V[(opcode & 0x0F00) >> 8];
- break;
+ delaytimer = V[(opcode & 0x0F00) >> 8];
+ break;
case 0x0018: // FX18 - Set the soundtimer to VX
- soundtimer = V[(opcode & 0x0F00) >> 8];
- break;
+ soundtimer = V[(opcode & 0x0F00) >> 8];
+ break;
case 0x001E: // FX1E - Add VX to I
- V[0xF] = ((I + V[(opcode & 0x0F00) >> 8]) > 0xFFF) ? 1 : 0;
- I += V[(opcode & 0x0F00) >> 8];
- break;
+ V[0xF] = ((I + V[(opcode & 0x0F00) >> 8]) > 0xFFF) ? 1 : 0;
+ I += V[(opcode & 0x0F00) >> 8];
+ break;
case 0x0029: // FX29 - Set I to the location of the sprite for char VX
- I = V[(opcode & 0x0F00) >> 8] * 0x5;
- break;
+ I = V[(opcode & 0x0F00) >> 8] * 0x5;
+ break;
case 0x0033: // FX33 - Store bin coded decimal of VX at I, I+1 and I+2
- memory[I] = V[(opcode & 0x0F00) >> 8] / 100;
- memory[I+1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
- memory[I+2] = V[(opcode & 0x0F00) >> 8] % 10;
- break;
+ memory[I] = V[(opcode & 0x0F00) >> 8] / 100;
+ memory[I+1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
+ memory[I+2] = V[(opcode & 0x0F00) >> 8] % 10;
+ break;
case 0x0055: // FX55 - Store V0 to VX in memory starting at I
- for (i = 0; i <= ((opcode & 0x0F00) >> 8); i++)
- memory[I + i] = V[i];
- I += ((opcode & 0x0F00) >> 8) + 1;
- break;
+ for (i = 0; i <= ((opcode & 0x0F00) >> 8); i++)
+ memory[I + i] = V[i];
+ I += ((opcode & 0x0F00) >> 8) + 1;
+ break;
case 0x0065: // FX65 - Fill V0 to VX with vals from memory starting at I
- for (i = 0; i <= ((opcode & 0x0F00) >> 8); i++)
- V[i] = memory[I + i];
- I += ((opcode & 0x0F00) >> 8) + 1;
- break;
+ for (i = 0; i <= ((opcode & 0x0F00) >> 8); i++)
+ V[i] = memory[I + i];
+ I += ((opcode & 0x0F00) >> 8) + 1;
+ break;
default:
- fprintf(stderr, "Unknown opcode: %x\n", opcode);
- return FALSE;
- }
- break;
+ fprintf(stderr, "Unknown opcode: %x\n", opcode);
+ return FALSE;
+ }
+ break;
default:
- fputs("Unimplemented opcode\n", stderr);
- return FALSE;
- }
- return TRUE;
+ fputs("Unimplemented opcode\n", stderr);
+ return FALSE;
+ }
+ return TRUE;
}
void
timers_update(struct Chip8 *chip8)
{
- if (delaytimer > 0)
- --delaytimer;
- if (soundtimer > 0)
- --soundtimer;
+ if (delaytimer > 0)
+ --delaytimer;
+ if (soundtimer > 0)
+ --soundtimer;
}
#undef V
@@ -353,79 +366,83 @@ timers_update(struct Chip8 *chip8)
int
evts(struct Chip8 *chip8)
{
- int i;
- SDL_Event e;
- while (SDL_PollEvent(&e))
- {
- if (e.type == SDL_QUIT || e.key.keysym.sym == SDLK_ESCAPE)
- return FALSE;
- if (e.type == SDL_KEYDOWN)
- for (i = 0; i < 16; i++)
- if (e.key.keysym.sym == keymap[i])
- chip8->keys[i] = TRUE;
- if (e.type == SDL_KEYUP)
- for (i = 0; i < 16; i++)
- if (e.key.keysym.sym == keymap[i])
- chip8->keys[i] = FALSE;
- }
- return TRUE;
+ int i;
+ SDL_Event e;
+
+ while (SDL_PollEvent(&e)) {
+ if (e.type == SDL_QUIT || e.key.keysym.sym == SDLK_ESCAPE)
+ return FALSE;
+ if (e.type == SDL_KEYDOWN)
+ for (i = 0; i < 16; i++)
+ if (e.key.keysym.sym == keymap[i])
+ chip8->keys[i] = TRUE;
+ if (e.type == SDL_KEYUP)
+ for (i = 0; i < 16; i++)
+ if (e.key.keysym.sym == keymap[i])
+ chip8->keys[i] = FALSE;
+ }
+ return TRUE;
}
void
render(SDL_Renderer *ren, SDL_Texture *tex, struct Chip8 *chip8)
{
- int i;
- uint32_t pixels[2048];
- chip8->drawflag = FALSE;
- for (i = 0; i < 2048; i++) {
- uint8_t pixel = chip8->gfx[i];
- pixels[i] = (0x00FFFFFF * pixel) | 0xFF000000;
+ int i;
+ uint32_t pixels[2048];
+ uint8_t pixel;
+
+ chip8->drawflag = FALSE;
+ for (i = 0; i < 2048; i++) {
+ pixel = chip8->gfx[i];
+ pixels[i] = (0x00FFFFFF * pixel) | 0xFF000000;
+ }
+ SDL_UpdateTexture(tex, NULL, pixels, 64 * sizeof(Uint32));
+ SDL_RenderClear(ren);
+ SDL_RenderCopy(ren, tex, NULL, NULL);
+ SDL_RenderPresent(ren);
}
- SDL_UpdateTexture(tex, NULL, pixels, 64 * sizeof(Uint32));
- SDL_RenderClear(ren);
- SDL_RenderCopy(ren, tex, NULL, NULL);
- SDL_RenderPresent(ren);
-}
int
main(int argc, char **argv)
{
- int w = 1024, h = 512;
- srand(time(NULL));
+ int w = 1024, h = 512;
- if (argc != 2) {
- fprintf(stderr, "Usage: %s [ROM]\n", argv[0]);
- return EXIT_FAILURE;
- }
- if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
- fputs("Cannot initialize SDL. Exiting. . .\n", stderr);
- return EXIT_FAILURE;
- }
- SDL_Window *win = SDL_CreateWindow("CHIP-8 Emulator", SDL_WINDOWPOS_UNDEFINED,
- SDL_WINDOWPOS_UNDEFINED, w, h,
- SDL_WINDOW_SHOWN);
- SDL_Renderer *ren = SDL_CreateRenderer(win, -1, 0);
- SDL_RenderSetLogicalSize(ren, w, h);
- SDL_Texture *tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888,
- SDL_TEXTUREACCESS_STREAMING, 64, 32);
- if (!win || !ren || !tex) {
- fprintf(stderr, "SDL error. Exiting. . .\n%s\n", SDL_GetError());
- return EXIT_FAILURE;
- }
+ srand(time(NULL));
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s [ROM]\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
+ fputs("Cannot initialize SDL. Exiting. . .\n", stderr);
+ return EXIT_FAILURE;
+ }
+ SDL_Window *win = SDL_CreateWindow("CHIP-8 Emulator", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, w, h,
+ SDL_WINDOW_SHOWN);
+ SDL_Renderer *ren = SDL_CreateRenderer(win, -1, 0);
+ SDL_RenderSetLogicalSize(ren, w, h);
+ SDL_Texture *tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_STREAMING, 64, 32);
+ if (!win || !ren || !tex) {
+ fprintf(stderr, "SDL error. Exiting. . .\n%s\n", SDL_GetError());
+ return EXIT_FAILURE;
+ }
- struct Chip8 chip8;
- chip8_init(&chip8);
- if (!romload(&chip8, argv[1]))
- return EXIT_FAILURE;
- for (; evts(&chip8); usleep(1500)) {
- emulate(&chip8);
- if (chip8.drawflag)
- render(ren, tex, &chip8);
- }
+ struct Chip8 chip8;
+ chip8_init(&chip8);
+ if (!romload(&chip8, argv[1]))
+ return EXIT_FAILURE;
+
+ while (evts(&chip8)) {
+ emulate(&chip8);
+ if (chip8.drawflag)
+ render(ren, tex, &chip8);
+ usleep(1500);
+ }
- SDL_DestroyTexture(tex);
- SDL_DestroyRenderer(ren);
- SDL_DestroyWindow(win);
- SDL_Quit();
- return EXIT_SUCCESS;
+ SDL_DestroyTexture(tex);
+ SDL_DestroyRenderer(ren);
+ SDL_DestroyWindow(win);
+ SDL_Quit();
+ return EXIT_SUCCESS;
}