From 76d89eb9973671726dc7fffaf22b06a7a77be550 Mon Sep 17 00:00:00 2001 From: dweller <dweller@cabin.digital> Date: Wed, 26 Mar 2025 17:31:51 +0200 Subject: build ''system''; decode metaprog; disasm --- .gitignore | 1 + bits.c | 15 --- build/x11 | 14 ++ clean | 2 + fnt.c | 19 --- instr.c | 149 --------------------- main.c | 343 ------------------------------------------------- sources/bits.c | 15 +++ sources/fnt.c | 19 +++ sources/instr.c | 102 +++++++++++++++ sources/main.c | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++ sources/meta/disasm.c | 41 ++++++ sources/meta/undef.c | 36 ++++++ 13 files changed, 580 insertions(+), 526 deletions(-) create mode 100644 .gitignore delete mode 100644 bits.c create mode 100755 build/x11 create mode 100755 clean delete mode 100644 fnt.c delete mode 100644 instr.c delete mode 100644 main.c create mode 100644 sources/bits.c create mode 100644 sources/fnt.c create mode 100644 sources/instr.c create mode 100644 sources/main.c create mode 100644 sources/meta/disasm.c create mode 100644 sources/meta/undef.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4f588e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +artifacts/ diff --git a/bits.c b/bits.c deleted file mode 100644 index a6b7887..0000000 --- a/bits.c +++ /dev/null @@ -1,15 +0,0 @@ -#define iota __COUNTER__ - -#define bit(x) (1 << (x)) - -#define KB bit(10) -#define MB bit(11) -#define GB bit(12) - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned long long u64; - -typedef u8 bool; -#define true 1 -#define false 0 diff --git a/build/x11 b/build/x11 new file mode 100755 index 0000000..a383438 --- /dev/null +++ b/build/x11 @@ -0,0 +1,14 @@ +#!/bin/sh -e + +bench() +{ + if [ x = "x$(which time)" ]; then + $@ + echo "time not installed" + else + time $@ + fi +} + +>&2 bench cc -std=c89 -Wall -Wextra sources/main.c -static -o artifacts/xip-8 +>&2 echo "------------------------------------------------\n" diff --git a/clean b/clean new file mode 100755 index 0000000..1dd2ea1 --- /dev/null +++ b/clean @@ -0,0 +1,2 @@ +#!/bin/sh -e +rm -rf artifacts/* diff --git a/fnt.c b/fnt.c deleted file mode 100644 index ca45865..0000000 --- a/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/instr.c b/instr.c deleted file mode 100644 index bef859d..0000000 --- a/instr.c +++ /dev/null @@ -1,149 +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; - -typedef void (*instr_func)(chip8* c8, chip8_op op, u16 nnn, u8 x, u8 y, u8 n, u8 kk); - - -const char* chip8_disasm_fmts[C8_OP_CNT] = -{ - "ILL unknown", - "CLS", - "RET", - "SYS %03X", - "JP %03X", - "CALL %03X", - "LD I, %03X", - "JP V0, %03X", - "SE V%-2x, %-2d", - "SNE V%-2x, %-2d", - "LD V%-2x, %-2d", - "ADD V%-2x, %-2d", - "RND V%-2x, %-2d", - "SKP V%-2x", - "SKNP V%-2x", - "LD V%-2x, DT", - "LD V%-2x, K", - "LD DT, V%-2x", - "LD ST, V%-2x", - "ADD I, V%-2x", - "LD F, V%-2x", - "LD B, V%-2x", - "LD [I], V%-2x", - "LD V%-2x, [I]", - "SE V%-2x, V%-2x", - "LD V%-2x, V%-2x", - "OR V%-2x, V%-2x", - "AND V%-2x, V%-2x", - "XOR V%-2x, V%-2x", - "ADD V%-2x, V%-2x", - "SUB V%-2x, V%-2x", - "SHR V%-2x, V%-2x", - "SUBN V%-2x, V%-2x", - "SHL V%-2x, V%-2x", - "SNE V%-2x, V%-2x", - "DRW V%-2x, V%-2x, %-1d" -}; - -void c8_decode(u8* code, u16 offset, instr_func func, chip8* c8); -void c8_disasm(chip8* c8, chip8_op op, u16 nnn, u8 x, u8 y, u8 n, u8 kk); -void c8_do(chip8* c8, chip8_op op, u16 nnn, u8 x, u8 y, u8 n, u8 kk); - -void c8_decode(u8* code, u16 offset, instr_func func, chip8* c8) -{ - chip8_op op = C8_ILL; - u16 word, instr, nnn; - u8 o, x, y, n, kk; - - 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); - - if(o == 0 && nnn == 0x0E0) op = C8_CLS; - else if(o == 0 && nnn == 0x0EE) op = C8_RET; - else if(o == 0) op = C8_SYS; - else if(o == 1) op = C8_JP; - else if(o == 2) op = C8_CALL; - else if(o == 0xA) op = C8_LDI; - else if(o == 0xB) op = C8_JPV; - else if(o == 3) op = C8_SEB; - else if(o == 4) op = C8_SNEB; - else if(o == 6) op = C8_LD; - else if(o == 7) op = C8_ADDB; - else if(o == 0xC) op = C8_RND; - else if(o == 0xE && kk == 0x9E) op = C8_SKP; - else if(o == 0xE && kk == 0xA1) op = C8_SKNP; - else if(o == 0xF && kk == 0x07) op = C8_MVDT; - else if(o == 0xF && kk == 0x0A) op = C8_LDK; - else if(o == 0xF && kk == 0x15) op = C8_LDDT; - else if(o == 0xF && kk == 0x18) op = C8_LDST; - else if(o == 0xF && kk == 0x1E) op = C8_ADDI; - else if(o == 0xF && kk == 0x29) op = C8_HEX; - else if(o == 0xF && kk == 0x33) op = C8_BCD; - else if(o == 0xF && kk == 0x55) op = C8_SAVE; - else if(o == 0xF && kk == 0x65) op = C8_RESTORE; - else if(o == 5 && n == 0) op = C8_SE; - else if(o == 8 && n == 0) op = C8_MOVE; - else if(o == 8 && n == 1) op = C8_OR; - else if(o == 8 && n == 2) op = C8_AND; - else if(o == 8 && n == 3) op = C8_XOR; - else if(o == 8 && n == 4) op = C8_ADD; - else if(o == 8 && n == 5) op = C8_SUB; - else if(o == 8 && n == 6) op = C8_SHR; - else if(o == 8 && n == 7) op = C8_SUBN; - else if(o == 8 && n == 0xE) op = C8_SHL; - else if(o == 9 && n == 0) op = C8_SNE; - else if(o == 0xD) op = C8_DRW; - - func(c8, op, nnn, x, y, n, kk); -} - -void c8_disasm(chip8* c8, chip8_op op, u16 nnn, u8 x, u8 y, u8 kk, u8 n); -void c8_do(chip8* c8, chip8_op op, u16 nnn, u8 x, u8 y, u8 kk, u8 n); - diff --git a/main.c b/main.c deleted file mode 100644 index c082914..0000000 --- a/main.c +++ /dev/null @@ -1,343 +0,0 @@ -#define _DEFAULT_SOURCE -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <time.h> - -#include <endian.h> - -#include "bits.c" -#include "fnt.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; - -#include "instr.c" - -#define V mem.sys.v -#define STACK mem.sys.stack -#define DISPLAY mem.sys.disp -#define FONT mem.sys.font -#define RAM mem.ram - - -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; -} - -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]); - } - } -} - -void _c8_loop(chip8* c8, bool disasm, u16 from, u16 len) -{ - u16 to = 0; - u16 pc = 0; - - assert(c8); - - if(disasm) - { - pc = c8->pc; - c8->pc = from; - to = from + len*2; - } - - c8->running = true; - while(c8->running) - { - int tmp; - u16 word, instr, nnn; - u8 o, x, y, n, kk; - - if(c8->pc >= sizeof(c8->mem)) - { - printf("PC Overflow!\n"); - c8->running = false; - break; - } - - if(c8->pc & 0x0001) - { - printf("PC is not aligned!\n"); - c8->running = false; - break; - } - - word = *(u16*)(c8->RAM + c8->pc); - instr = be16toh(word); - o = (instr & 0xF000) >> 12; - nnn = (instr & 0x0FFF); - x = (instr & 0x0F00) >> 8; - y = (instr & 0x00F0) >> 4; - n = (instr & 0x000F); - kk = (instr & 0x00FF); - - printf("%04X: ", c8->pc); - switch(o) - { - case 1: - printf(" %04X JP 0x%03X\n", instr, nnn); - if(disasm) break; - c8->pc = nnn - 2; - break; - - case 2: - printf(" %04X CALL 0x%03X\n", instr, nnn); - if(disasm) break; - c8->STACK[c8->sp++] = c8->pc; /* docs says ++sp then stack[sp] = pc ??? */ - c8->pc = nnn - 2; - break; - - case 3: - printf(" %04X SE V%x, 0x%02X\n", instr, x, kk); - if(disasm) break; - if(c8->V[x] == kk) c8->pc += 2; - break; - - case 5: - printf(" %04X SE V%x, V%x\n", instr, x, y); - if(disasm) break; - if(c8->V[x] == c8->V[y]) c8->pc += 2; - break; - - case 6: - printf(" %04X LD V%x, 0x%02X\n", instr, x, kk); - if(disasm) break; - c8->V[x] = kk; - break; - - case 7: - printf(" %04X ADD V%x, 0x%02X\n", instr, x, kk); - if(disasm) break; - tmp = (int)c8->V[x] + (int)kk; - c8->V[0xf] = (tmp > 255); - /* c8->V[x] = (u8)tmp; /* spec says Vf not set */ - break; - - case 8: - { - switch(n) - { - case 4: - printf(" %04X ADD V%x, V%x\n", instr, x, y); - if(disasm) break; - tmp = (int)c8->V[x] + (int)c8->V[y]; - c8->V[0xf] = (tmp > 255); - c8->V[x] = (u8)tmp; - break; - - default: - printf(" %04X Unknown instruction\n", instr); - if(disasm) break; - c8->running = false; - break; - } - } - break; - - case 0xA: - printf(" %04X LD I, 0x%03X\n", instr, nnn); - if(disasm) break; - c8->i = nnn; - break; - - case 0xC: - printf(" %04X RND V%x, 0x%02X\n", instr, x, kk); - if(disasm) break; - c8->V[x] = (rand() % 256) & kk; - break; - - case 0xD: - printf(" %04X DRW V%x, V%x, %d\n", instr, x, y, n); - if(disasm) break; - /* TODO: implement */ - break; - - case 0xE: - if(kk == 0x9E) - { - printf(" %04X SKP V%x\n", instr, x); - if(disasm) break; - if(c8->keys & bit(x)) c8->pc += 2; - } - else if(kk == 0xA1) - { - printf(" %04X SKNP V%x\n", instr, x); - if(disasm) break; - if(!(c8->keys & bit(x))) c8->pc += 2; - } - else - { - printf(" %04X Unknown instruction\n", instr); - if(disasm) break; - c8->running = false; - } - break; - - case 0xF: - if(kk == 0x07) - { - printf(" %04X LD V%x, DT\n", instr, x); - if(disasm) break; - c8->V[x] = c8->dt; - } - else if(kk == 0x15) - { - printf(" %04X LD DT, V%x\n", instr, x); - if(disasm) break; - c8->dt= c8->V[x]; - } - else - { - printf(" %04X Unknown instruction\n", instr); - if(disasm) break; - c8->running = false; - } - break; - - default: - printf(" %04X Unknown instruction\n", instr); - if(disasm) break; - c8->running = false; - break; - } - - if(!disasm) c8_dump_state(c8, false); - - c8->pc += 2; - c8->cycles++; - if((c8->cycles % C8_CYCLES_PER_FRAME) == 0) - { - if(c8->dt) c8->dt--; - if(c8->st) c8->st--; - } - - if(disasm && (c8->pc >= to)) c8->running = false; - } - - if(disasm) c8->pc = pc; -} - -void c8_disam(chip8* c8, u16 from, u16 len) { _c8_loop(c8, true, from, len); } -void c8_loop(chip8* c8) { _c8_loop(c8, false, 0, 0); } - - -int main(int argc, char** argv) -{ - FILE* f = NULL; - chip8 c8 = {0}; - - srand(time(NULL)); - - c8_reset(&c8); - - if(argc > 1) - { - u64 sz, got = 0; - - f = fopen(argv[1], "r"); - if(!f) return 1; - - fseek(f, 0, SEEK_END); - sz = (u64)ftell(f); - rewind(f); - - if(sz >= (sizeof(c8.RAM) - 512)) return 2; - - got = fread(c8.RAM + C8_RESET_VECTOR, 1, sz, f); - if(got != sz) return 3; - - fclose(f); - } - else - { - c8.RAM[C8_RESET_VECTOR + iota] = 0x60; - c8.RAM[C8_RESET_VECTOR + iota] = 0x04; - - c8.RAM[C8_RESET_VECTOR + iota] = 0x61; - c8.RAM[C8_RESET_VECTOR + iota] = 0x03; - - c8.RAM[C8_RESET_VECTOR + iota] = 0x72; - c8.RAM[C8_RESET_VECTOR + iota] = 0x01; - - c8.RAM[C8_RESET_VECTOR + iota] = 0x80; - c8.RAM[C8_RESET_VECTOR + iota] = 0x14; - - c8.RAM[C8_RESET_VECTOR + iota] = 0x30; - c8.RAM[C8_RESET_VECTOR + iota] = 0x10; - - c8.RAM[C8_RESET_VECTOR + iota] = 0x12; - c8.RAM[C8_RESET_VECTOR + iota] = 0x04; - } - - printf("Disasm:\n"); - c8_disam(&c8, C8_RESET_VECTOR, 32); - - printf("\nExec:\n"); - c8_loop(&c8); - - return 0; -} diff --git a/sources/bits.c b/sources/bits.c new file mode 100644 index 0000000..a6b7887 --- /dev/null +++ b/sources/bits.c @@ -0,0 +1,15 @@ +#define iota __COUNTER__ + +#define bit(x) (1 << (x)) + +#define KB bit(10) +#define MB bit(11) +#define GB bit(12) + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long long u64; + +typedef u8 bool; +#define true 1 +#define false 0 diff --git a/sources/fnt.c b/sources/fnt.c new file mode 100644 index 0000000..ca45865 --- /dev/null +++ b/sources/fnt.c @@ -0,0 +1,19 @@ +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 new file mode 100644 index 0000000..8c0b132 --- /dev/null +++ b/sources/instr.c @@ -0,0 +1,102 @@ +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); \ + \ + 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" diff --git a/sources/main.c b/sources/main.c new file mode 100644 index 0000000..56630df --- /dev/null +++ b/sources/main.c @@ -0,0 +1,350 @@ +#define _DEFAULT_SOURCE +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <time.h> + +#include <endian.h> + +#include "bits.c" +#include "fnt.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; + +#include "instr.c" + +#define V mem.sys.v +#define STACK mem.sys.stack +#define DISPLAY mem.sys.disp +#define FONT mem.sys.font +#define RAM mem.ram + + +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; +} + +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]); + } + } +} + +void _c8_loop(chip8* c8, bool disasm, u16 from, u16 len) +{ + u16 to = 0; + u16 pc = 0; + + assert(c8); + + if(disasm) + { + pc = c8->pc; + c8->pc = from; + to = from + len*2; + } + + c8->running = true; + while(c8->running) + { + int tmp; + u16 word, instr, nnn; + u8 o, x, y, n, kk; + + if(c8->pc >= sizeof(c8->mem)) + { + printf("PC Overflow!\n"); + c8->running = false; + break; + } + + if(c8->pc & 0x0001) + { + printf("PC is not aligned!\n"); + c8->running = false; + break; + } + + word = *(u16*)(c8->RAM + c8->pc); + instr = be16toh(word); + o = (instr & 0xF000) >> 12; + nnn = (instr & 0x0FFF); + x = (instr & 0x0F00) >> 8; + y = (instr & 0x00F0) >> 4; + n = (instr & 0x000F); + kk = (instr & 0x00FF); + + printf("%04X: ", c8->pc); + switch(o) + { + case 1: + printf(" %04X JP 0x%03X\n", instr, nnn); + if(disasm) break; + c8->pc = nnn - 2; + break; + + case 2: + printf(" %04X CALL 0x%03X\n", instr, nnn); + if(disasm) break; + c8->STACK[c8->sp++] = c8->pc; /* docs says ++sp then stack[sp] = pc ??? */ + c8->pc = nnn - 2; + break; + + case 3: + printf(" %04X SE V%x, 0x%02X\n", instr, x, kk); + if(disasm) break; + if(c8->V[x] == kk) c8->pc += 2; + break; + + case 5: + printf(" %04X SE V%x, V%x\n", instr, x, y); + if(disasm) break; + if(c8->V[x] == c8->V[y]) c8->pc += 2; + break; + + case 6: + printf(" %04X LD V%x, 0x%02X\n", instr, x, kk); + if(disasm) break; + c8->V[x] = kk; + break; + + case 7: + printf(" %04X ADD V%x, 0x%02X\n", instr, x, kk); + if(disasm) break; + tmp = (int)c8->V[x] + (int)kk; + c8->V[0xf] = (tmp > 255); + /* c8->V[x] = (u8)tmp; /* spec says Vf not set */ + break; + + case 8: + { + switch(n) + { + case 4: + printf(" %04X ADD V%x, V%x\n", instr, x, y); + if(disasm) break; + tmp = (int)c8->V[x] + (int)c8->V[y]; + c8->V[0xf] = (tmp > 255); + c8->V[x] = (u8)tmp; + break; + + default: + printf(" %04X Unknown instruction\n", instr); + if(disasm) break; + c8->running = false; + break; + } + } + break; + + case 0xA: + printf(" %04X LD I, 0x%03X\n", instr, nnn); + if(disasm) break; + c8->i = nnn; + break; + + case 0xC: + printf(" %04X RND V%x, 0x%02X\n", instr, x, kk); + if(disasm) break; + c8->V[x] = (rand() % 256) & kk; + break; + + case 0xD: + printf(" %04X DRW V%x, V%x, %d\n", instr, x, y, n); + if(disasm) break; + /* TODO: implement */ + break; + + case 0xE: + if(kk == 0x9E) + { + printf(" %04X SKP V%x\n", instr, x); + if(disasm) break; + if(c8->keys & bit(x)) c8->pc += 2; + } + else if(kk == 0xA1) + { + printf(" %04X SKNP V%x\n", instr, x); + if(disasm) break; + if(!(c8->keys & bit(x))) c8->pc += 2; + } + else + { + printf(" %04X Unknown instruction\n", instr); + if(disasm) break; + c8->running = false; + } + break; + + case 0xF: + if(kk == 0x07) + { + printf(" %04X LD V%x, DT\n", instr, x); + if(disasm) break; + c8->V[x] = c8->dt; + } + else if(kk == 0x15) + { + printf(" %04X LD DT, V%x\n", instr, x); + if(disasm) break; + c8->dt= c8->V[x]; + } + else + { + printf(" %04X Unknown instruction\n", instr); + if(disasm) break; + c8->running = false; + } + break; + + default: + printf(" %04X Unknown instruction\n", instr); + if(disasm) break; + c8->running = false; + break; + } + + if(!disasm) c8_dump_state(c8, false); + + c8->pc += 2; + c8->cycles++; + if((c8->cycles % C8_CYCLES_PER_FRAME) == 0) + { + if(c8->dt) c8->dt--; + if(c8->st) c8->st--; + } + + if(disasm && (c8->pc >= to)) c8->running = false; + } + + if(disasm) c8->pc = pc; +} + + +int main(int argc, char** argv) +{ + u64 sz = 0; + FILE* f = NULL; + chip8 c8 = {0}; + + srand(time(NULL)); + + c8_reset(&c8); + + if(argc > 1) + { + u64 got = 0; + + f = fopen(argv[1], "r"); + if(!f) return 1; + + fseek(f, 0, SEEK_END); + sz = (u64)ftell(f); + rewind(f); + + if(sz >= (sizeof(c8.RAM) - 512)) return 2; + + got = fread(c8.RAM + C8_RESET_VECTOR, 1, sz, f); + if(got != sz) return 3; + + fclose(f); + } + else + { + c8.RAM[C8_RESET_VECTOR + iota] = 0x60; + c8.RAM[C8_RESET_VECTOR + iota] = 0x04; + + c8.RAM[C8_RESET_VECTOR + iota] = 0x61; + c8.RAM[C8_RESET_VECTOR + iota] = 0x03; + + c8.RAM[C8_RESET_VECTOR + iota] = 0x72; + c8.RAM[C8_RESET_VECTOR + iota] = 0x01; + + c8.RAM[C8_RESET_VECTOR + iota] = 0x80; + c8.RAM[C8_RESET_VECTOR + iota] = 0x14; + + c8.RAM[C8_RESET_VECTOR + iota] = 0x30; + c8.RAM[C8_RESET_VECTOR + iota] = 0x10; + + c8.RAM[C8_RESET_VECTOR + iota] = 0x12; + c8.RAM[C8_RESET_VECTOR + iota] = 0x04; + + sz = iota; + } + + printf("Disasm:\n"); + { + u64 i; + char buf[512] = {0}; + + for(i = 0; i < sz; i += 2) + { + u16 pc = C8_RESET_VECTOR + i; + c8_disasm(c8.RAM, pc, buf); + printf("%04X: %s\n", pc, buf); + } + } + + return 0; +} diff --git a/sources/meta/disasm.c b/sources/meta/disasm.c new file mode 100644 index 0000000..2a33aed --- /dev/null +++ b/sources/meta/disasm.c @@ -0,0 +1,41 @@ +#define X_C8_ILL sprintf(usrdat, "ILL unknown") +#define X_C8_CLS sprintf(usrdat, "CLS") +#define X_C8_RET sprintf(usrdat, "RET") +#define X_C8_SYS sprintf(usrdat, "SYS 0x%03X", nnn) +#define X_C8_JP sprintf(usrdat, "JP 0x%03X", nnn) +#define X_C8_CALL sprintf(usrdat, "CALL 0x%03X", nnn) +#define X_C8_LDI sprintf(usrdat, "LD I, 0x%03X", nnn) +#define X_C8_JPV sprintf(usrdat, "JP V0, 0x%03X", nnn) +#define X_C8_SEB sprintf(usrdat, "SE V%x, %d", x, kk) +#define X_C8_SNEB sprintf(usrdat, "SNE V%x, %d", x, kk) +#define X_C8_LD sprintf(usrdat, "LD V%x, %d", x, kk) +#define X_C8_ADDB sprintf(usrdat, "ADD V%x, %d", x, kk) +#define X_C8_RND sprintf(usrdat, "RND V%x, %d", x, kk) +#define X_C8_SKP sprintf(usrdat, "SKP V%x", x) +#define X_C8_SKNP sprintf(usrdat, "SKNP V%x", x) +#define X_C8_MVDT sprintf(usrdat, "LD V%x, DT", x) +#define X_C8_LDK sprintf(usrdat, "LD V%x, K", x) +#define X_C8_LDDT sprintf(usrdat, "LD DT, V%x", x) +#define X_C8_LDST sprintf(usrdat, "LD ST, V%x", x) +#define X_C8_ADDI sprintf(usrdat, "ADD I, V%x", x) +#define X_C8_HEX sprintf(usrdat, "LD F, V%x", x) +#define X_C8_BCD sprintf(usrdat, "LD B, V%x", x) +#define X_C8_SAVE sprintf(usrdat, "LD [I], V%x", x) +#define X_C8_RESTORE sprintf(usrdat, "LD V%x, [I]", x) +#define X_C8_SE sprintf(usrdat, "SE V%x, V%x", x, y) +#define X_C8_MOVE sprintf(usrdat, "LD V%x, V%x", x, y) +#define X_C8_OR sprintf(usrdat, "OR V%x, V%x", x, y) +#define X_C8_AND sprintf(usrdat, "AND V%x, V%x", x, y) +#define X_C8_XOR sprintf(usrdat, "XOR V%x, V%x", x, y) +#define X_C8_ADD sprintf(usrdat, "ADD V%x, V%x", x, y) +#define X_C8_SUB sprintf(usrdat, "SUB V%x, V%x", x, y) +#define X_C8_SHR sprintf(usrdat, "SHR V%x, V%x", x, y) +#define X_C8_SUBN sprintf(usrdat, "SUBN V%x, V%x", x, y) +#define X_C8_SHL sprintf(usrdat, "SHL V%x, V%x", x, y) +#define X_C8_SNE sprintf(usrdat, "SNE V%x, V%x", x, y) +#define X_C8_DRW sprintf(usrdat, "DRW V%x, V%x, %d", x, y, n) + +c8_decode_generate(disasm) + +#include "undef.c" + diff --git a/sources/meta/undef.c b/sources/meta/undef.c new file mode 100644 index 0000000..1863e9b --- /dev/null +++ b/sources/meta/undef.c @@ -0,0 +1,36 @@ +#undef X_C8_ILL +#undef X_C8_CLS +#undef X_C8_RET +#undef X_C8_SYS +#undef X_C8_JP +#undef X_C8_CALL +#undef X_C8_LDI +#undef X_C8_JPV +#undef X_C8_SEB +#undef X_C8_SNEB +#undef X_C8_LD +#undef X_C8_ADDB +#undef X_C8_RND +#undef X_C8_SKP +#undef X_C8_SKNP +#undef X_C8_MVDT +#undef X_C8_LDK +#undef X_C8_LDDT +#undef X_C8_LDST +#undef X_C8_ADDI +#undef X_C8_HEX +#undef X_C8_BCD +#undef X_C8_SAVE +#undef X_C8_RESTORE +#undef X_C8_SE +#undef X_C8_MOVE +#undef X_C8_OR +#undef X_C8_AND +#undef X_C8_XOR +#undef X_C8_ADD +#undef X_C8_SUB +#undef X_C8_SHR +#undef X_C8_SUBN +#undef X_C8_SHL +#undef X_C8_SNE +#undef X_C8_DRW -- cgit v1.2.3