From 750cd23d7afac165502defa1d259ace00ca0e414 Mon Sep 17 00:00:00 2001 From: dweller Date: Wed, 26 Mar 2025 20:37:01 +0200 Subject: clean up chip-8 into its own file --- sources/chip8.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++ sources/fnt.c | 19 ----- sources/instr.c | 110 -------------------------- sources/main.c | 104 +------------------------ sources/meta/disasm.c | 3 + sources/meta/exec.c | 34 ++++++-- sources/meta/undef.c | 3 + 7 files changed, 249 insertions(+), 236 deletions(-) create mode 100644 sources/chip8.c delete mode 100644 sources/fnt.c delete mode 100644 sources/instr.c diff --git a/sources/chip8.c b/sources/chip8.c new file mode 100644 index 0000000..f5a28a8 --- /dev/null +++ b/sources/chip8.c @@ -0,0 +1,212 @@ +#define C8_RESET_VECTOR 0x200 +#define C8_CYCLES_PER_FRAME 1000 + +static const u8 fnt[] = +{ + 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 */ +}; + + +typedef struct +{ + u16 pc; + u8 sp; + + u16 i; + u16 keys; + + u64 cycles; + + /* timers: */ + u8 dt; /* - delay */ + u8 st; /* - sound */ + + bool running; + + union + { + struct + { + u8 v[16]; + u64 disp[32]; + u8 font[sizeof(fnt)]; + u16 stack[16]; + + } sys; + u8 ram[4*KB]; + } mem; + +} chip8; + +#define V mem.sys.v +#define STACK mem.sys.stack +#define DISPLAY mem.sys.disp +#define FONT mem.sys.font +#define RAM mem.ram + +typedef enum +{ + C8_ILL, +/* Onnn = 0,1,2,A,B */ +/* 00E0 - CLS */ C8_CLS, +/* 00EE - RET */ C8_RET, +/* 0nnn - SYS addr */ C8_SYS, +/* 1nnn - JP addr */ C8_JP, +/* 2nnn - CALL addr */ C8_CALL, +/* Annn - LD I, addr */ C8_LDI, +/* Bnnn - JP V0, addr */ C8_JPV, +/* Oxkk = 3,4,6,7,C,E,F */ +/* 3xkk - SE Vx, byte */ C8_SEB, +/* 4xkk - SNE Vx, byte */ C8_SNEB, +/* 6xkk - LD Vx, byte */ C8_LD, +/* 7xkk - ADD Vx, byte */ C8_ADDB, +/* Cxkk - RND Vx, byte */ C8_RND, +/* Ex9E - SKP Vx */ C8_SKP, +/* ExA1 - SKNP Vx */ C8_SKNP, +/* Fx07 - LD Vx, DT */ C8_MVDT, +/* Fx0A - LD Vx, K */ C8_LDK, +/* Fx15 - LD DT, Vx */ C8_LDDT, +/* Fx18 - LD ST, Vx */ C8_LDST, +/* Fx1E - ADD I, Vx */ C8_ADDI, +/* Fx29 - LD F, Vx */ C8_HEX, +/* Fx33 - LD B, Vx */ C8_BCD, +/* Fx55 - LD [I], Vx */ C8_SAVE, +/* Fx65 - LD Vx, [I] */ C8_RESTORE, +/* Oxyn = 5,8,9,D */ +/* 5xy0 - SE Vx, Vy */ C8_SE, +/* 8xy0 - LD Vx, Vy */ C8_MOVE, +/* 8xy1 - OR Vx, Vy */ C8_OR, +/* 8xy2 - AND Vx, Vy */ C8_AND, +/* 8xy3 - XOR Vx, Vy */ C8_XOR, +/* 8xy4 - ADD Vx, Vy */ C8_ADD, +/* 8xy5 - SUB Vx, Vy */ C8_SUB, +/* 8xy6 - SHR Vx {, Vy} */ C8_SHR, +/* 8xy7 - SUBN Vx, Vy */ C8_SUBN, +/* 8xyE - SHL Vx {, Vy} */ C8_SHL, +/* 9xy0 - SNE Vx, Vy */ C8_SNE, +/* Dxyn - DRW Vx, Vy, nibble */ C8_DRW, + C8_OP_CNT + +} chip8_op; + + +void c8_reset(chip8* c8) +{ + assert(c8); + assert(sizeof(c8->mem) > sizeof(fnt)); + assert(sizeof(c8->mem) >= 4*KB); + + memcpy(c8->FONT, fnt, sizeof(fnt)); + + c8->pc = C8_RESET_VECTOR; + c8->running = true; +} + +void c8_dump_state(chip8* c8, bool stack) +{ + int i = 0; + + for(i = 0; i < (int)sizeof(c8->V); i += 4) + { + printf(" V%x: %02X (%3d) ", i+0, c8->V[i+0], c8->V[i+0]); + printf("V%x: %02X (%3d) ", i+1, c8->V[i+1], c8->V[i+1]); + printf("V%x: %02X (%3d) ", i+2, c8->V[i+2], c8->V[i+2]); + printf("V%x: %02X (%3d)\n", i+3, c8->V[i+3], c8->V[i+3]); + } + + printf(" I:%04X SP: %02X DT: %02X ST: %02X CYCLES: %llu\n", + c8->i, c8->sp, c8->dt, c8->st, c8->cycles); + + if(stack) + { + printf("stack:\n"); + for(i = 0; i < (int)sizeof(c8->STACK); i += 2) + { + printf(" %-2d: %04X ", i+0, c8->STACK[i+0]); + printf("%-2d: %04X\n", i+1, c8->STACK[i+1]); + } + } +} + + + +#define c8_decode_generate(name) \ +void c8_##name(u8* code, u16 offset, void* usrdat) \ +{ \ + u16 word, instr, nnn; \ + u8 o, x, y, n, kk; \ + \ + (void)usrdat; \ + \ + word = *(u16*)(code + offset); \ + instr = be16toh(word); \ + o = (instr & 0xF000) >> 12; \ + nnn = (instr & 0x0FFF); \ + x = (instr & 0x0F00) >> 8; \ + y = (instr & 0x00F0) >> 4; \ + n = (instr & 0x000F); \ + kk = (instr & 0x00FF); \ + \ + (void)o; \ + (void)nnn; \ + (void)x; \ + (void)y; \ + (void)n; \ + (void)kk; \ + \ + X_C8_PRELUDE; \ + \ + if(o == 0 && nnn == 0x0E0) X_C8_CLS; \ + else if(o == 0 && nnn == 0x0EE) X_C8_RET; \ + else if(o == 0) X_C8_SYS; \ + else if(o == 1) X_C8_JP; \ + else if(o == 2) X_C8_CALL; \ + else if(o == 0xA) X_C8_LDI; \ + else if(o == 0xB) X_C8_JPV; \ + else if(o == 3) X_C8_SEB; \ + else if(o == 4) X_C8_SNEB; \ + else if(o == 6) X_C8_LD; \ + else if(o == 7) X_C8_ADDB; \ + else if(o == 0xC) X_C8_RND; \ + else if(o == 0xE && kk == 0x9E) X_C8_SKP; \ + else if(o == 0xE && kk == 0xA1) X_C8_SKNP; \ + else if(o == 0xF && kk == 0x07) X_C8_MVDT; \ + else if(o == 0xF && kk == 0x0A) X_C8_LDK; \ + else if(o == 0xF && kk == 0x15) X_C8_LDDT; \ + else if(o == 0xF && kk == 0x18) X_C8_LDST; \ + else if(o == 0xF && kk == 0x1E) X_C8_ADDI; \ + else if(o == 0xF && kk == 0x29) X_C8_HEX; \ + else if(o == 0xF && kk == 0x33) X_C8_BCD; \ + else if(o == 0xF && kk == 0x55) X_C8_SAVE; \ + else if(o == 0xF && kk == 0x65) X_C8_RESTORE; \ + else if(o == 5 && n == 0) X_C8_SE; \ + else if(o == 8 && n == 0) X_C8_MOVE; \ + else if(o == 8 && n == 1) X_C8_OR; \ + else if(o == 8 && n == 2) X_C8_AND; \ + else if(o == 8 && n == 3) X_C8_XOR; \ + else if(o == 8 && n == 4) X_C8_ADD; \ + else if(o == 8 && n == 5) X_C8_SUB; \ + else if(o == 8 && n == 6) X_C8_SHR; \ + else if(o == 8 && n == 7) X_C8_SUBN; \ + else if(o == 8 && n == 0xE) X_C8_SHL; \ + else if(o == 9 && n == 0) X_C8_SNE; \ + else if(o == 0xD) X_C8_DRW; \ + else X_C8_ILL; \ + \ + X_C8_EPILOGUE; \ +} diff --git a/sources/fnt.c b/sources/fnt.c deleted file mode 100644 index ca45865..0000000 --- a/sources/fnt.c +++ /dev/null @@ -1,19 +0,0 @@ -static const u8 fnt[] = -{ - 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 */ -}; diff --git a/sources/instr.c b/sources/instr.c deleted file mode 100644 index 72511f1..0000000 --- a/sources/instr.c +++ /dev/null @@ -1,110 +0,0 @@ -typedef enum -{ - C8_ILL, -/* Onnn = 0,1,2,A,B */ -/* 00E0 - CLS */ C8_CLS, -/* 00EE - RET */ C8_RET, -/* 0nnn - SYS addr */ C8_SYS, -/* 1nnn - JP addr */ C8_JP, -/* 2nnn - CALL addr */ C8_CALL, -/* Annn - LD I, addr */ C8_LDI, -/* Bnnn - JP V0, addr */ C8_JPV, -/* Oxkk = 3,4,6,7,C,E,F */ -/* 3xkk - SE Vx, byte */ C8_SEB, -/* 4xkk - SNE Vx, byte */ C8_SNEB, -/* 6xkk - LD Vx, byte */ C8_LD, -/* 7xkk - ADD Vx, byte */ C8_ADDB, -/* Cxkk - RND Vx, byte */ C8_RND, -/* Ex9E - SKP Vx */ C8_SKP, -/* ExA1 - SKNP Vx */ C8_SKNP, -/* Fx07 - LD Vx, DT */ C8_MVDT, -/* Fx0A - LD Vx, K */ C8_LDK, -/* Fx15 - LD DT, Vx */ C8_LDDT, -/* Fx18 - LD ST, Vx */ C8_LDST, -/* Fx1E - ADD I, Vx */ C8_ADDI, -/* Fx29 - LD F, Vx */ C8_HEX, -/* Fx33 - LD B, Vx */ C8_BCD, -/* Fx55 - LD [I], Vx */ C8_SAVE, -/* Fx65 - LD Vx, [I] */ C8_RESTORE, -/* Oxyn = 5,8,9,D */ -/* 5xy0 - SE Vx, Vy */ C8_SE, -/* 8xy0 - LD Vx, Vy */ C8_MOVE, -/* 8xy1 - OR Vx, Vy */ C8_OR, -/* 8xy2 - AND Vx, Vy */ C8_AND, -/* 8xy3 - XOR Vx, Vy */ C8_XOR, -/* 8xy4 - ADD Vx, Vy */ C8_ADD, -/* 8xy5 - SUB Vx, Vy */ C8_SUB, -/* 8xy6 - SHR Vx {, Vy} */ C8_SHR, -/* 8xy7 - SUBN Vx, Vy */ C8_SUBN, -/* 8xyE - SHL Vx {, Vy} */ C8_SHL, -/* 9xy0 - SNE Vx, Vy */ C8_SNE, -/* Dxyn - DRW Vx, Vy, nibble */ C8_DRW, - C8_OP_CNT - -} chip8_op; - - -#define c8_decode_generate(name) \ -void c8_##name(u8* code, u16 offset, void* usrdat) \ -{ \ - u16 word, instr, nnn; \ - u8 o, x, y, n, kk; \ - \ - (void)usrdat; \ - \ - word = *(u16*)(code + offset); \ - instr = be16toh(word); \ - o = (instr & 0xF000) >> 12; \ - nnn = (instr & 0x0FFF); \ - x = (instr & 0x0F00) >> 8; \ - y = (instr & 0x00F0) >> 4; \ - n = (instr & 0x000F); \ - kk = (instr & 0x00FF); \ - \ - (void)o; \ - (void)nnn; \ - (void)x; \ - (void)y; \ - (void)n; \ - (void)kk; \ - \ - if(o == 0 && nnn == 0x0E0) X_C8_CLS; \ - else if(o == 0 && nnn == 0x0EE) X_C8_RET; \ - else if(o == 0) X_C8_SYS; \ - else if(o == 1) X_C8_JP; \ - else if(o == 2) X_C8_CALL; \ - else if(o == 0xA) X_C8_LDI; \ - else if(o == 0xB) X_C8_JPV; \ - else if(o == 3) X_C8_SEB; \ - else if(o == 4) X_C8_SNEB; \ - else if(o == 6) X_C8_LD; \ - else if(o == 7) X_C8_ADDB; \ - else if(o == 0xC) X_C8_RND; \ - else if(o == 0xE && kk == 0x9E) X_C8_SKP; \ - else if(o == 0xE && kk == 0xA1) X_C8_SKNP; \ - else if(o == 0xF && kk == 0x07) X_C8_MVDT; \ - else if(o == 0xF && kk == 0x0A) X_C8_LDK; \ - else if(o == 0xF && kk == 0x15) X_C8_LDDT; \ - else if(o == 0xF && kk == 0x18) X_C8_LDST; \ - else if(o == 0xF && kk == 0x1E) X_C8_ADDI; \ - else if(o == 0xF && kk == 0x29) X_C8_HEX; \ - else if(o == 0xF && kk == 0x33) X_C8_BCD; \ - else if(o == 0xF && kk == 0x55) X_C8_SAVE; \ - else if(o == 0xF && kk == 0x65) X_C8_RESTORE; \ - else if(o == 5 && n == 0) X_C8_SE; \ - else if(o == 8 && n == 0) X_C8_MOVE; \ - else if(o == 8 && n == 1) X_C8_OR; \ - else if(o == 8 && n == 2) X_C8_AND; \ - else if(o == 8 && n == 3) X_C8_XOR; \ - else if(o == 8 && n == 4) X_C8_ADD; \ - else if(o == 8 && n == 5) X_C8_SUB; \ - else if(o == 8 && n == 6) X_C8_SHR; \ - else if(o == 8 && n == 7) X_C8_SUBN; \ - else if(o == 8 && n == 0xE) X_C8_SHL; \ - else if(o == 9 && n == 0) X_C8_SNE; \ - else if(o == 0xD) X_C8_DRW; \ - else X_C8_ILL; \ -} - -#include "meta/disasm.c" -#include "meta/exec.c" diff --git a/sources/main.c b/sources/main.c index 8c4ac97..2036b73 100644 --- a/sources/main.c +++ b/sources/main.c @@ -9,89 +9,12 @@ #include #include "bits.c" -#include "fnt.c" #include "log.c" +#include "chip8.c" +#include "meta/disasm.c" +#include "meta/exec.c" -#define C8_RESET_VECTOR 0x200 -#define C8_CYCLES_PER_FRAME 1000 - - -typedef struct -{ - u16 pc; - u8 sp; - - u16 i; - u16 keys; - - u64 cycles; - - /* timers: */ - u8 dt; /* - delay */ - u8 st; /* - sound */ - - bool running; - - union - { - struct - { - u8 v[16]; - u64 disp[32]; - u8 font[sizeof(fnt)]; - u16 stack[16]; - - } sys; - u8 ram[4*KB]; - } mem; - -} chip8; - -#define V mem.sys.v -#define STACK mem.sys.stack -#define DISPLAY mem.sys.disp -#define FONT mem.sys.font -#define RAM mem.ram - -#include "instr.c" - -void c8_reset(chip8* c8) -{ - assert(c8); - assert(sizeof(c8->mem) > sizeof(fnt)); - assert(sizeof(c8->mem) >= 4*KB); - - memcpy(c8->FONT, fnt, sizeof(fnt)); - - c8->pc = C8_RESET_VECTOR; - c8->running = true; -} - -void c8_dump_state(chip8* c8, bool stack) -{ - int i = 0; - - for(i = 0; i < (int)sizeof(c8->V); i += 4) - { - printf(" V%x: %02X (%-3d) ", i+0, c8->V[i+0], c8->V[i+0]); - printf("V%x: %02X (%-3d) ", i+1, c8->V[i+1], c8->V[i+1]); - printf("V%x: %02X (%-3d) ", i+2, c8->V[i+2], c8->V[i+2]); - printf("V%x: %02X (%-3d)\n", i+3, c8->V[i+3], c8->V[i+3]); - } - - printf(" I:%04X SP: %02X DT: %02X ST: %02X\n", c8->i, c8->sp, c8->dt, c8->st); - - if(stack) - { - printf("stack:\n"); - for(i = 0; i < (int)sizeof(c8->STACK); i += 2) - { - printf(" %-2d: %04X ", i+0, c8->STACK[i+0]); - printf("%-2d: %04X\n", i+1, c8->STACK[i+1]); - } - } -} int main(int argc, char** argv) { @@ -162,32 +85,11 @@ int main(int argc, char** argv) { char buf[512] = {0}; - if(c8.pc >= sizeof(c8.mem)) - { - report(ERR, "PC Overflow!\n"); - c8.running = false; - } - - if(c8.pc & 0x0001) - { - report(ERR, "PC is not aligned!\n"); - c8.running = false; - } - c8_disasm(c8.RAM, c8.pc, buf); printf("%04X: %s\n", c8.pc, buf); c8_exec(c8.RAM, c8.pc, &c8); c8_dump_state(&c8, false); - - c8.cycles++; - if((c8.cycles % C8_CYCLES_PER_FRAME) == 0) - { - if(c8.dt) c8.dt--; - if(c8.st) c8.st--; - } - - c8.pc += 2; } return 0; diff --git a/sources/meta/disasm.c b/sources/meta/disasm.c index 66c1478..82e715e 100644 --- a/sources/meta/disasm.c +++ b/sources/meta/disasm.c @@ -1,3 +1,6 @@ +#define X_C8_PRELUDE +#define X_C8_EPILOGUE + #define X_C8_ILL sprintf(usrdat, "%04X ILL unknown", instr) #define X_C8_CLS sprintf(usrdat, "%04X CLS", instr) #define X_C8_RET sprintf(usrdat, "%04X RET", instr) diff --git a/sources/meta/exec.c b/sources/meta/exec.c index b913390..a39aef2 100644 --- a/sources/meta/exec.c +++ b/sources/meta/exec.c @@ -1,11 +1,33 @@ -/* FIXME: add a one time init and deinit to generate macro */ -#define BEGIN \ -do{ \ - chip8* c8 = usrdat; \ - assert(c8); - +#define BEGIN do{ #define END }while(0) +#define X_C8_PRELUDE \ + chip8* c8 = usrdat; \ + assert(c8); \ +\ + if(c8->pc >= sizeof(c8->mem)) \ + { \ + report(ERR, "CHIP-8: PC(%04X) Overflow!\n", c8->pc); \ + c8->running = false; \ + } \ +\ + if(c8->pc & 0x0001) \ + { \ + report(ERR, "CHIP-8: PC(%04X) is not aligned!\n", c8->pc); \ + c8->running = false; \ + } + +#define X_C8_EPILOGUE \ +BEGIN \ + c8->cycles++; \ + if((c8->cycles % C8_CYCLES_PER_FRAME) == 0) \ + { \ + if(c8->dt) c8->dt--; \ + if(c8->st) c8->st--; \ + } \ + c8->pc += 2; \ +END + #define X_C8_ILL \ BEGIN \ c8->running = false; \ diff --git a/sources/meta/undef.c b/sources/meta/undef.c index 1863e9b..01ce25f 100644 --- a/sources/meta/undef.c +++ b/sources/meta/undef.c @@ -1,3 +1,6 @@ +#undef X_C8_PRELUDE +#undef X_C8_EPILOGUE + #undef X_C8_ILL #undef X_C8_CLS #undef X_C8_RET -- cgit v1.2.3