chip-8

chip-8 emulator

Initial commmit

Arjun Choudhary contact@arjunchoudhary.com

commit: a2e4208

2 files changed, 173 insertions(+), 0 deletions(-)
ADDMakefile+2-0
ADDmain.c+171-0
ADD · Makefile +2 -0
--- a/Makefile
+++ b/Makefile
@@ -0,0 +1,2 @@
+chip8: main.c
+	$(CC) main.c -o chip8 `sdl2-config --cflags --libs` -Wall -Wextra -pedantic -std=c99
ADD · main.c +171 -0
--- a/main.c
+++ b/main.c
@@ -0,0 +1,171 @@
+/*** includes ***/
+#include <SDL2/SDL.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+/*** data ***/
+// opcode store
+// All opcodes are 2 bytes and so are unsigned short
+unsigned short opcode;
+// 4KB of RAM
+unsigned char memory[4096];
+// CPU Register
+// 16 general purpose 8 bit registers
+unsigned char V[16];
+// Index or Address Register
+unsigned short I;
+// Program counter | A psudo register that points to the next instruction on the
+// stack Instruction pointer being my preffered nomenclature
+unsigned short pc;
+// Display containing 2048 pixels in an array
+unsigned char gfx[64 * 32];
+// Timer registers that countdown to 0 at 60Hz
+unsigned char delay_timer;
+unsigned char sound_timer;
+//
+unsigned short stack[16];
+unsigned short stack_pointer;
+
+// Fontset used by CHIP 8
+// Also used to draw sprits using XOR
+// DEC   HEX    BIN         RESULT    DEC   HEX    BIN         RESULT
+// 240   0xF0   1111 0000    ****     240   0xF0   1111 0000    ****
+// 144   0x90   1001 0000    *  *      16   0x10   0001 0000       *
+// 144   0x90   1001 0000    *  *      32   0x20   0010 0000      *
+// 144   0x90   1001 0000    *  *      64   0x40   0100 0000     *
+// 240   0xF0   1111 0000    ****      64   0x40   0100 0000     *
+
+unsigned char chip8_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
+};
+
+// Keypad
+unsigned char keypad[16];
+
+// Screen dimension constants
+const int SCREEN_WIDTH = 640;
+const int SCREEN_HEIGHT = 320;
+
+/*** initialize cpu ***/
+void chip8_initialize(void) {
+  pc = 0x200;        // program counter starts at 0x200 or 512
+  opcode = 0;        // reset current opcode
+  I = 0;             // reset current index register
+  stack_pointer = 0; // reset stack pointer
+  printf("Chip 8 Initialized successfully \n");
+  // Load fontset into memory 
+  //for (int i = 0; i < 80; i++) {
+  //      memory[i] = fontset[i];
+  //  }
+  memcpy(memory, chip8_fontset, sizeof(chip8_fontset));
+}
+
+/*** load rom ***/
+void chip8_load_program(char *filename) {
+  FILE *program = fopen(filename, "rb");
+
+  // get file size
+  fseek(program, 0, SEEK_END);
+  long buf_len = ftell(program);
+  rewind(program);
+
+  // load data into buffer
+  char *buf = malloc((buf_len + 1) * sizeof(char));
+  fread(buf, buf_len, 1, program);
+  printf("Rom loaded succesfully \n");
+  printf("Rom size: %zu bytes \n", buf_len);
+  fclose(program);
+
+  // load rom into memory
+  for (int i = 0; i < buf_len; i++) {
+    memory[0x200 + i] = buf[i];
+    // Big endian so check last two values from the right
+    printf("Byte successfully read: %08X \n", buf[i]);
+  }
+  // clear buffer
+  free(buf);
+}
+
+/*** initialize display ***/
+int chip8_init_display (){
+  SDL_Init(SDL_INIT_VIDEO);
+  // Init Window struct
+  SDL_Window *window;
+  // Init window
+   window =
+      SDL_CreateWindow(
+        "CHIP8", 
+        SDL_WINDOWPOS_CENTERED, 
+        SDL_WINDOWPOS_CENTERED,
+        SCREEN_WIDTH,
+        SCREEN_HEIGHT, 
+        0);
+  // Init renderer struct
+  SDL_Renderer* renderer;
+  // Init renderer
+    renderer =  
+      SDL_CreateRenderer(
+        window, 
+        -1, 
+        SDL_RENDERER_ACCELERATED);
+  //SDL Render color (background)
+  SDL_SetRenderDrawColor( renderer, 0, 0, 0, 0 );
+  // Clear the current color and use the one specified above 
+  SDL_RenderClear( renderer );
+  // Shape 
+  SDL_Rect rectangle;
+    rectangle.x = 0;
+    rectangle.y = 0;
+    rectangle.w = 90;
+    rectangle.h = 100;
+
+  SDL_SetRenderDrawColor( renderer, 0, 0, 255, 255 );
+  SDL_RenderFillRect( renderer, &rectangle );
+  SDL_RenderPresent(renderer);
+
+
+  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+    printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
+    return -1;
+  }
+
+  // Check that the window was successfully created
+  if (window == NULL) {
+    // In the case that the window could not be made...
+    printf("Could not create window: %s\n", SDL_GetError());
+    return -1;
+  }
+  SDL_Delay(3000);
+  // Pause execution for 3000 milliseconds, for example
+  // Close and destroy the window
+  SDL_DestroyWindow(window);
+  // Clean up
+  SDL_Quit();
+  return 0;
+}
+
+int main(int argc, char *argv[]) {
+  chip8_initialize();
+  chip8_load_program(argv[1]);
+  chip8_init_display();
+  return 0;
+}