summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xMakefile19
-rw-r--r--chip8.c150
-rw-r--r--chip8.h24
-rw-r--r--roms/Breakout [Carmelo Cortez, 1979].ch8bin0 -> 232 bytes
-rw-r--r--roms/a.ch8bin0 -> 27 bytes
-rw-r--r--roms/e.asm22
-rw-r--r--roms/e.ch8bin0 -> 25 bytes
-rw-r--r--ui.c35
-rw-r--r--ui.h4
-rw-r--r--util.c14
-rw-r--r--util.h9
12 files changed, 278 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#ifdef _WIN32
+#include <window.h>
+#else
+#include <unistd.h>
+#include <pthread.h>
+#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
--- /dev/null
+++ b/roms/Breakout [Carmelo Cortez, 1979].ch8
Binary files differ
diff --git a/roms/a.ch8 b/roms/a.ch8
new file mode 100644
index 0000000..f445d49
--- /dev/null
+++ b/roms/a.ch8
Binary files 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
--- /dev/null
+++ b/roms/e.ch8
Binary files 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 <ncurses.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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 <stdlib.h>
+#include <stdio.h>
+
+#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 <stdint.h>
+
+#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);