From 1ea493d0d11d19dd3777f3e2646bce19929f786a Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 9 Sep 2019 20:25:22 -0400 Subject: initial commit --- .gitignore | 1 + Makefile | 19 ++++ chip8.c | 150 +++++++++++++++++++++++++++++++ chip8.h | 24 +++++ roms/Breakout [Carmelo Cortez, 1979].ch8 | Bin 0 -> 232 bytes roms/a.ch8 | Bin 0 -> 27 bytes roms/e.asm | 22 +++++ roms/e.ch8 | Bin 0 -> 25 bytes ui.c | 35 ++++++++ ui.h | 4 + util.c | 14 +++ util.h | 9 ++ 12 files changed, 278 insertions(+) create mode 100644 .gitignore create mode 100755 Makefile create mode 100644 chip8.c create mode 100644 chip8.h create mode 100644 roms/Breakout [Carmelo Cortez, 1979].ch8 create mode 100644 roms/a.ch8 create mode 100644 roms/e.asm create mode 100644 roms/e.ch8 create mode 100644 ui.c create mode 100644 ui.h create mode 100644 util.c create mode 100644 util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1062ad7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +chip8 diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..b504d98 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +all: CC=gcc +win: CC=x86_64-w64-mingw32-gcc + +CFLAGS = -O3 -Wall -std=c99 $(shell pkg-config --cflags ncursesw) + +all: BIN = chip8 +win: BIN = chip8.exe + +all: executable +win: executable + +all: LDFLAGS = -lncursesw -ltinfow -lpthread +win: LDFLAGS = ./win/pdcurses.a + +executable: chip8.c ui.c util.c + $(CC) $(CFLAGS) -o $(BIN) chip8.c ui.c util.c $(LDFLAGS) + +clean: + $(RM) chip8 diff --git a/chip8.c b/chip8.c new file mode 100644 index 0000000..c48f543 --- /dev/null +++ b/chip8.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#include "ui.h" +#include "util.h" +#include "chip8.h" + +#define ROM_FILE "roms/a.ch8" + +static void load_rom(); +static void init_vm(); +static void push_top_of_stack(u16 val); +static void vm_thread(void* v); + +chip8_vm vm; + +void init_vm() { + memset(&vm, 0, sizeof(chip8_vm)); + vm.PC = 0x200; // start of chip8 programs +} + +void load_rom() { + FILE* f = fopen(ROM_FILE, "r"); + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + vm.rom = malloc(fsize + 1); + vm.rom_size = 0x200 + fsize; + if (fread(vm.rom, 1, fsize, f) != fsize) { + printf("err: failed to read rom fully\n"); + exit(1); + } + + fclose(f); +} + +void push_top_of_stack(u16 val) { + for (u16 i = vm.SP; i < vm.stack_count; i++) { + if (i >= 15) { + exit(1); + } + vm.stack[i+1] = vm.stack[i]; + } + vm.stack[vm.SP] = val; +} + +void vm_thread(void* v) { + if (vm.PC > vm.rom_size) { + return; + } + + // read 2 bytes and convert to big-endian + u16 instr = htons(vm.rom[(vm.PC) - 0x1FF]<<8 | vm.rom[(vm.PC) - 0x200]); + + char str[5]; + sprintf(str, "%x", instr); + + switch (*str) { + case '0': + if (instr == 0x00E0) { + //clearscreen + } else if (instr == 0x00EE) { + vm.PC = vm.stack[vm.SP--]; + } + break; + case '1': + vm.PC = hex_str(str+1); + break; + case '2': + vm.SP++; + push_top_of_stack(vm.PC); + vm.PC = hex_str(str+1); + break; + case '3': + if (vm.Vx[hex_char(str[1])] == hex_str(str+2)) { + vm.PC += 0x2; + } + break; + case '4': + if (vm.Vx[hex_char(str[1])] != hex_str(str+2)) { + vm.PC += 0x2; + } + break; + case '5': + if (vm.Vx[hex_char(str[1])] == vm.Vx[hex_char(str[2])]) { + vm.PC += 0x2; + } + break; + case '6': + vm.Vx[hex_char(str[1])] = hex_str(str+2); + break; + case '7': + vm.Vx[hex_char(str[1])] += hex_str(str+2); + break; + case '8': + switch(str[3]) { + case '0': + vm.Vx[hex_char(str[1])] = vm.Vx[hex_char(str[2])]; + break; + case '1': + vm.Vx[hex_char(str[1])] |= vm.Vx[hex_char(str[2])]; + break; + case '2': + vm.Vx[hex_char(str[1])] &= vm.Vx[hex_char(str[2])]; + break; + } + } + + vm.PC += 0x2; +} + +int main(void) { + init_vm(); + load_rom(); + +#ifdef _WIN32 + DWORD WINAPI loop(void* data) { + while(1) { + vm_thread(0); + sleep(1); + } + return 0; + } + HANDLE thread = CreateThread(NULL, 0, loop, NULL, 0, NULL); +#else + void *loop(void) { + while(1) { + vm_thread(0); + usleep(100); + } + return 0; + } + pthread_t t; pthread_create(&t, NULL, (void*)loop, (void*)0); +#endif + + init_curses(); + curses_thread(0); + + return 0; +} diff --git a/chip8.h b/chip8.h new file mode 100644 index 0000000..4ea248f --- /dev/null +++ b/chip8.h @@ -0,0 +1,24 @@ +#pragma once + +#include "util.h" + +typedef struct { + u8* rom; + u16 rom_size; + + u16 PC; + + u16 stack[16]; + u16 stack_pos; + u16 stack_count; + + u8 DT; + u8 ST; + + u8 SP; + u16 I; + + u8 Vx[16]; +} chip8_vm; + +extern chip8_vm vm; diff --git a/roms/Breakout [Carmelo Cortez, 1979].ch8 b/roms/Breakout [Carmelo Cortez, 1979].ch8 new file mode 100644 index 0000000..70b50db Binary files /dev/null and b/roms/Breakout [Carmelo Cortez, 1979].ch8 differ diff --git a/roms/a.ch8 b/roms/a.ch8 new file mode 100644 index 0000000..f445d49 Binary files /dev/null and b/roms/a.ch8 differ diff --git a/roms/e.asm b/roms/e.asm new file mode 100644 index 0000000..2dd3761 --- /dev/null +++ b/roms/e.asm @@ -0,0 +1,22 @@ +CLS + +LD V0, 0 +LD V1, 0 +LD V2, 0 + +loop: + +LD F, V0 +LD I, esprite +DRW V1, V2, 5 +ADD V1, 5 +ADD V2, 6 + +JP loop + +esprite: +db %11110000, + %10000000, + %11110000, + %10000000, + %11110000, diff --git a/roms/e.ch8 b/roms/e.ch8 new file mode 100644 index 0000000..e890b81 Binary files /dev/null and b/roms/e.ch8 differ diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..d48f3e1 --- /dev/null +++ b/ui.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +#include "chip8.h" + +void init_curses() { + initscr(); + curs_set(0); + noecho(); + nodelay(stdscr, 1); + clear(); +} + +void curses_thread(void* v) { + char c; + while(1) { + c = getch(); + if (c == 'q') { + endwin(); + exit(1); + } + mvaddstr(0, 0, "V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 VA VB VC VD VE VF"); + char buf[5]; + for (int i = 0; i < 16; i++) { + sprintf(buf, "%i", vm.Vx[i]); + mvaddstr(1, i * 4, buf); + } + usleep(100); + } +} + + diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..ea588df --- /dev/null +++ b/ui.h @@ -0,0 +1,4 @@ +#pragma once + +void curses_thread(void* v); +void init_curses(); diff --git a/util.c b/util.c new file mode 100644 index 0000000..a8c2f94 --- /dev/null +++ b/util.c @@ -0,0 +1,14 @@ +#include +#include + +#include "util.h" + +u16 hex_str(char* str) { + return (u16)strtol(str, NULL, 16); +} + +u16 hex_char(char c) { + char buf[2]; + sprintf(buf, "%c", c); + return (u16)strtol(buf, NULL, 16); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..17760b6 --- /dev/null +++ b/util.h @@ -0,0 +1,9 @@ +#include + +#define u8 uint8_t +#define u16 uint16_t +#define s8 int8_t +#define s16 int16_t + +u16 hex_char(char c); +u16 hex_str(char* str); -- cgit v1.2.3-101-g0448