chip8

CHIP-8 emulator
git clone git://git.christosmarg.xyz/chip8.git
Log | Files | Refs | README | LICENSE

commit af4315096adec14d0d40a647cac92ddb4135ba75
parent 88bebe70bbf6950b64d83c69c1c86c8c18d21e00
Author: Christos Margiolis <christos@margiolis.net>
Date:   Wed, 26 May 2021 18:54:28 +0300

no support for windows

Diffstat:
MLICENSE | 2+-
MMakefile | 41++++++++++++++++++++---------------------
Mchip8.1 | 2+-
Mchip8.c | 150++++++++++++++++++++++++++++---------------------------------------------------
Mconfig.mk | 21+++++----------------
5 files changed, 79 insertions(+), 137 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -1,6 +1,6 @@ MIT License -(c) 2020-Present Christos Margiolis <christos@christosmarg.xyz> +(c) 2020-Present Christos Margiolis <christos@margiolis.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in diff --git a/Makefile b/Makefile @@ -1,5 +1,5 @@ # See LICENSE file for copyright and license details. -# chip8 - a minimal CHIP-8 emulator +# chip8 - CHIP-8 emulator .POSIX: include config.mk @@ -8,47 +8,46 @@ BIN = chip8 DIST = ${BIN}-${VERSION} MAN1 = ${BIN}.1 -EXT = c SRC = chip8.c -OBJ = ${SRC:.${EXT}=.o} +OBJ = ${SRC:.c=.o} all: options ${BIN} options: @echo ${BIN} build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" ${BIN}: ${OBJ} ${CC} ${LDFLAGS} ${OBJ} -o $@ -.${EXT}.o: +.c.o: ${CC} -c ${CFLAGS} $< dist: clean - ${MKDIR} ${DIST} - ${CP} -R roms ${MAN1} ${SRC} config.mk LICENSE Makefile README.md ${DIST} - ${TAR} ${DIST}.tar ${DIST} - ${GZIP} ${DIST}.tar - ${RM_DIR} ${DIST} + mkdir -p ${DIST} + cp -R roms chip8.1 chip8.c config.mk LICENSE Makefile README.md ${DIST} + tar -cf ${DIST}.tar ${DIST} + gzip ${DIST}.tar + rm -rf ${DIST} run: ./${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 755 ${DESTDIR}${BIN_DIR}/${BIN} - chmod 644 ${DESTDIR}${MAN_DIR}/${MAN1} + mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${MANPREFIX}/man1 + cp -f ${BIN} ${DESTDIR}${PREFIX}/bin + cp -f ${MAN1} ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MANPREFIX}/man1/${MAN1} + chmod 755 ${DESTDIR}${PREFIX}/bin/${BIN} + chmod 644 ${DESTDIR}${MANPREFIX}/man1/${MAN1} uninstall: - ${RM} ${DESTDIR}${BIN_DIR}/${BIN} - ${RM} ${DESTDIR}${MAN_DIR}/${MAN1} + rm -f ${DESTDIR}${PREFIX}/bin/${BIN} \ + ${DESTDIR}${MANPREFIX}/man1/${MAN1} clean: - ${RM} ${BIN} ${OBJ} ${DIST}.tar.gz + rm -f ${BIN} ${OBJ} ${DIST}.tar.gz *.core .PHONY: all options clean dist install uninstall run diff --git a/chip8.1 b/chip8.1 @@ -12,4 +12,4 @@ reads a CHIP\-8 ROM and executes it. It uses the SDL2 library as a rendering API. .Sh AUTHORS -.An Christos Margiolis Aq Mt christos@christosmarg.xyz +.An Christos Margiolis Aq Mt christos@margiolis.net diff --git a/chip8.c b/chip8.c @@ -1,22 +1,16 @@ /* See LICENSE file for copyright and license details. */ +#include <sys/types.h> + +#include <err.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> +#include <unistd.h> #include <SDL2/SDL.h> -#ifdef _WIN_32 -#include <Windows.h> -typedef unsigned int u_int32_t -typedef unsigned short u_int16_t -typedef unsigned char u_int8_t -#else /* !_WIN_32 */ -#include <sys/types.h> -#include <unistd.h> -#endif /* _WIN_32 */ - #define VX_MASK(x) ((x & 0x0f00) >> 8) #define VY_MASK(x) ((x & 0x00f0) >> 4) #define NN_MASK(x) (x & 0x00ff) @@ -24,31 +18,29 @@ typedef unsigned char u_int8_t #define EXECUTE(pc) do { pc += 2; } while (0) struct chip8 { - u_int16_t stack[16]; - u_int16_t I; - u_int16_t opcode; - u_int16_t pc; - u_int16_t sp; - u_int8_t mem[4096]; - u_int8_t gfx[64 * 32]; - u_int8_t V[16]; - u_int8_t keys[16]; - u_int8_t delaytimer; - u_int8_t soundtimer; - u_int8_t drawflag; + uint16_t stack[16]; + uint16_t I; + uint16_t opcode; + uint16_t pc; + uint16_t sp; + uint8_t mem[4096]; + uint8_t gfx[64 * 32]; + uint8_t V[16]; + uint8_t keys[16]; + uint8_t delaytimer; + uint8_t soundtimer; + uint8_t drawflag; }; static void chip8_init(struct chip8 *); -static void romload(struct chip8 *, const char *); +static void rom_load(struct chip8 *, const char *); static void emulate(struct chip8 *); static int decode(struct chip8 *); -static int evhandle(struct chip8 *); +static int handle_events(struct chip8 *); static void render(SDL_Renderer *, SDL_Texture *, struct chip8 *); -static void warn(const char *, ...); -static void die(const char *, ...); static char *argv0; -static const u_int8_t keymap[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, @@ -71,7 +63,7 @@ static const u_int8_t keymap[16] = { static void chip8_init(struct chip8 *chip8) { - u_int8_t fontset[80] = { + uint8_t fontset[80] = { 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 0x20, 0x60, 0x20, 0x20, 0x70, // 1 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 @@ -109,30 +101,28 @@ chip8_init(struct chip8 *chip8) } static void -romload(struct chip8 *chip8, const char *fpath) +rom_load(struct chip8 *chip8, const char *fpath) { FILE *rom; char *buf; - size_t res, romsize; + size_t res, romsiz; int i; if ((rom = fopen(fpath, "rb")) == NULL) - die("fopen: %s", fpath); + err(1, "fopen: %s", fpath); fseek(rom, 0, SEEK_END); - romsize = ftell(rom); + romsiz = ftell(rom); rewind(rom); - - if ((buf = malloc(romsize + 1)) == NULL) - die("malloc:"); - if ((res = fread(buf, sizeof(char), romsize, rom)) != romsize) - die("fread:"); - buf[romsize] = '\0'; - if (romsize < (4092 - 512)) - for (i = 0; i < romsize; i++) + if ((buf = malloc(romsiz + 1)) == NULL) + err(1, "malloc"); + if ((res = fread(buf, sizeof(char), romsiz, rom)) != romsiz) + err(1, "fread"); + buf[romsiz] = '\0'; + if (romsiz < (4092 - 512)) + for (i = 0; i < romsiz; i++) mem[i + 512] = buf[i]; else - die("ROM cannot fit into memory"); - + errx(1, "ROM cannot fit into memory"); fclose(rom); free(buf); } @@ -156,8 +146,8 @@ static int decode(struct chip8 *chip8) { int yl, xl, i, keypress = 0; - u_int16_t h, pixel; - u_int8_t VX, VY; + uint16_t h, pixel; + uint8_t VX, VY; switch (opcode & 0xF000) { case 0x0000: // 00E_ @@ -170,7 +160,7 @@ decode(struct chip8 *chip8) pc = stack[--sp]; break; default: - warn("unknown opcode: %x\n", opcode); + warnx("unknown opcode: %x\n", opcode); return 0; } break; @@ -233,7 +223,7 @@ decode(struct chip8 *chip8) V[VX_MASK(opcode)] <<= 1; break; default: - warn("unknown opcode: %x\n", opcode); + warnx("unknown opcode: %x\n", opcode); return 0; } break; @@ -279,7 +269,7 @@ decode(struct chip8 *chip8) EXECUTE(pc); break; default: - warn("unknown opcode: %x\n", opcode); + warnx("unknown opcode: %x\n", opcode); return 0; } break; @@ -327,12 +317,12 @@ decode(struct chip8 *chip8) I += (VX_MASK(opcode)) + 1; break; default: - warn("unknown opcode: %x\n", opcode); + warnx("unknown opcode: %x\n", opcode); return 0; } break; default: - warn("unimplemented opcode\n"); + warnx("unimplemented opcode\n"); return 0; } return 1; @@ -352,7 +342,7 @@ decode(struct chip8 *chip8) #undef drawflag static int -evhandle(struct chip8 *chip8) +handle_events(struct chip8 *chip8) { SDL_Event e; int i; @@ -377,7 +367,7 @@ evhandle(struct chip8 *chip8) static void render(SDL_Renderer *ren, SDL_Texture *tex, struct chip8 *chip8) { - u_int32_t pixels[2048]; + uint32_t pixels[2048]; int i; chip8->drawflag = 0; @@ -389,38 +379,6 @@ render(SDL_Renderer *ren, SDL_Texture *tex, struct chip8 *chip8) SDL_RenderPresent(ren); } -static void -warn(const char *fmt, ...) -{ - va_list args; - - fprintf(stderr, "%s: ", argv0); - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); -} - -static void -die(const char *fmt, ...) -{ - va_list args; - - fprintf(stderr, "%s: ", argv0); - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - if (fmt[0] && fmt[strlen(fmt)-1] == ':') { - fputc(' ', stderr); - perror(NULL); - } else - fputc('\n', stderr); - - exit(EXIT_FAILURE); -} - int main(int argc, char *argv[]) { @@ -433,11 +391,16 @@ main(int argc, char *argv[]) argv0 = *argv; srand(time(NULL)); if (argc != 2) { - fprintf(stderr, "usage: %s rom", argv0); + fprintf(stderr, "usage: %s rom\n", argv0); return 1; } + if ((chip8 = malloc(sizeof(struct chip8))) == NULL) + err(1, "malloc"); + chip8_init(chip8); + rom_load(chip8, argv[1]); + if (SDL_Init(SDL_INIT_EVERYTHING) < 0) - die("SDL_Init: %s", SDL_GetError()); + errx(1, "SDL_Init: %s", SDL_GetError()); win = SDL_CreateWindow("CHIP-8 Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, @@ -448,24 +411,15 @@ main(int argc, char *argv[]) SDL_TEXTUREACCESS_STREAMING, 64, 32); if (!win || !ren || !tex) - die("SDL error: %s", SDL_GetError()); - if ((chip8 = malloc(sizeof(struct chip8))) == NULL) - die("malloc:"); - - chip8_init(chip8); - romload(chip8, argv[1]); - + errx(1, "SDL error: %s", SDL_GetError()); for (;;) { - if (!evhandle(chip8)) + if (!handle_events(chip8)) break; emulate(chip8); if (chip8->drawflag) render(ren, tex, chip8); -#ifdef _WIN_32 - Sleep(1); -#else /* !_WIN_32 */ + /* FIXME: VERY slow on some machines */ usleep(1500); -#endif /* _WIN_32 */ } free(chip8); @@ -474,5 +428,5 @@ main(int argc, char *argv[]) SDL_DestroyWindow(win); SDL_Quit(); - return EXIT_SUCCESS; + return 0; } diff --git a/config.mk b/config.mk @@ -1,15 +1,14 @@ # See LICENSE file for copyright and license details. # chip8 version -VERSION = 0 +VERSION = 0.1 # paths PREFIX = /usr/local -MAN_DIR = ${PREFIX}/share/man/man1 -BIN_DIR = ${PREFIX}/bin +MANPREFIX = ${PREFIX}/share/man # includes and libs -INCS = -Iinclude -LIBS = -Llib -lSDL2 +INCS = -Iinclude -I${PREFIX}/include +LIBS = -Llib -L${PREFIX}/lib -lSDL2 # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \ @@ -17,15 +16,5 @@ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \ CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = ${LIBS} -# utils -CP = cp -f -RM = rm -f -RM_DIR = rm -rf -MV = mv -MKDIR = mkdir -p -RM_DIR = rm -rf -TAR = tar -cf -GZIP = gzip - # compiler -CC = gcc +CC = cc