summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordweller <dweller@cabin.digital>2025-03-26 18:25:34 +0200
committerdweller <dweller@cabin.digital>2025-03-26 18:25:34 +0200
commit42e9b31e0d7324106a65ad9ff42ea2377a80fa51 (patch)
treeceee87f9e0067b6d5c71f5e728fe0b3fd0fd8b72
parent76d89eb9973671726dc7fffaf22b06a7a77be550 (diff)
fix disasm not showing instruction hex; implement a few instructions exec; add report logger
-rwxr-xr-xbuild/x112
-rw-r--r--sources/instr.c8
-rw-r--r--sources/log.c40
-rw-r--r--sources/main.c230
-rw-r--r--sources/meta/disasm.c72
-rw-r--r--sources/meta/exec.c82
6 files changed, 204 insertions, 230 deletions
diff --git a/build/x11 b/build/x11
index a383438..7489e93 100755
--- a/build/x11
+++ b/build/x11
@@ -10,5 +10,5 @@ bench()
fi
}
->&2 bench cc -std=c89 -Wall -Wextra sources/main.c -static -o artifacts/xip-8
+>&2 bench cc -std=c89 -Wall -Wextra -Wno-comment sources/main.c -static -o artifacts/xip-8
>&2 echo "------------------------------------------------\n"
diff --git a/sources/instr.c b/sources/instr.c
index 8c0b132..72511f1 100644
--- a/sources/instr.c
+++ b/sources/instr.c
@@ -61,6 +61,13 @@ void c8_##name(u8* code, u16 offset, void* usrdat) \
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; \
@@ -100,3 +107,4 @@ void c8_##name(u8* code, u16 offset, void* usrdat) \
}
#include "meta/disasm.c"
+#include "meta/exec.c"
diff --git a/sources/log.c b/sources/log.c
new file mode 100644
index 0000000..ba0aa86
--- /dev/null
+++ b/sources/log.c
@@ -0,0 +1,40 @@
+typedef enum log_kind
+{
+ LK_DEBUG,
+ LK_INFO,
+ LK_WARN,
+ LK_ERROR,
+ LK_FATAL,
+
+ LK_ENUM_LEN
+
+} log_kind;
+
+static char* log_kind_names[LK_ENUM_LEN] =
+{
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "FATAL",
+};
+
+#define DBG LK_DEBUG, __FILE__, __LINE__
+#define INFO LK_INFO, __FILE__, __LINE__
+#define WARN LK_WARN, __FILE__, __LINE__
+#define ERR LK_ERROR, __FILE__, __LINE__
+#define FATAL LK_FATAL, __FILE__, __LINE__
+
+void report(log_kind kind, const char* file, int line, const char* fmt, ...)
+{
+ va_list ap;
+
+ /* TODO: log levels */
+
+ printf("[%s] %s:%d - ", log_kind_names[kind], file, line);
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+
+ if(kind == LK_FATAL) abort();
+}
diff --git a/sources/main.c b/sources/main.c
index 56630df..8c4ac97 100644
--- a/sources/main.c
+++ b/sources/main.c
@@ -4,11 +4,13 @@
#include <string.h>
#include <assert.h>
#include <time.h>
+#include <stdarg.h>
#include <endian.h>
#include "bits.c"
#include "fnt.c"
+#include "log.c"
#define C8_RESET_VECTOR 0x200
@@ -46,14 +48,13 @@ typedef struct
} 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
+#include "instr.c"
void c8_reset(chip8* c8)
{
@@ -64,6 +65,7 @@ void c8_reset(chip8* c8)
memcpy(c8->FONT, fnt, sizeof(fnt));
c8->pc = C8_RESET_VECTOR;
+ c8->running = true;
}
void c8_dump_state(chip8* c8, bool stack)
@@ -91,197 +93,6 @@ void c8_dump_state(chip8* c8, bool stack)
}
}
-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;
@@ -346,5 +157,38 @@ int main(int argc, char** argv)
}
}
+ printf("\nExec:\n");
+ while(c8.running)
+ {
+ 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 2a33aed..66c1478 100644
--- a/sources/meta/disasm.c
+++ b/sources/meta/disasm.c
@@ -1,39 +1,39 @@
-#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)
+#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)
+#define X_C8_SYS sprintf(usrdat, "%04X SYS 0x%03X", instr, nnn)
+#define X_C8_JP sprintf(usrdat, "%04X JP 0x%03X", instr, nnn)
+#define X_C8_CALL sprintf(usrdat, "%04X CALL 0x%03X", instr, nnn)
+#define X_C8_LDI sprintf(usrdat, "%04X LD I, 0x%03X", instr, nnn)
+#define X_C8_JPV sprintf(usrdat, "%04X JP V0, 0x%03X", instr, nnn)
+#define X_C8_SEB sprintf(usrdat, "%04X SE V%x, %d", instr, x, kk)
+#define X_C8_SNEB sprintf(usrdat, "%04X SNE V%x, %d", instr, x, kk)
+#define X_C8_LD sprintf(usrdat, "%04X LD V%x, %d", instr, x, kk)
+#define X_C8_ADDB sprintf(usrdat, "%04X ADD V%x, %d", instr, x, kk)
+#define X_C8_RND sprintf(usrdat, "%04X RND V%x, %d", instr, x, kk)
+#define X_C8_SKP sprintf(usrdat, "%04X SKP V%x", instr, x)
+#define X_C8_SKNP sprintf(usrdat, "%04X SKNP V%x", instr, x)
+#define X_C8_MVDT sprintf(usrdat, "%04X LD V%x, DT", instr, x)
+#define X_C8_LDK sprintf(usrdat, "%04X LD V%x, K", instr, x)
+#define X_C8_LDDT sprintf(usrdat, "%04X LD DT, V%x", instr, x)
+#define X_C8_LDST sprintf(usrdat, "%04X LD ST, V%x", instr, x)
+#define X_C8_ADDI sprintf(usrdat, "%04X ADD I, V%x", instr, x)
+#define X_C8_HEX sprintf(usrdat, "%04X LD F, V%x", instr, x)
+#define X_C8_BCD sprintf(usrdat, "%04X LD B, V%x", instr, x)
+#define X_C8_SAVE sprintf(usrdat, "%04X LD [I], V%x", instr, x)
+#define X_C8_RESTORE sprintf(usrdat, "%04X LD V%x, [I]", instr, x)
+#define X_C8_SE sprintf(usrdat, "%04X SE V%x, V%x", instr, x, y)
+#define X_C8_MOVE sprintf(usrdat, "%04X LD V%x, V%x", instr, x, y)
+#define X_C8_OR sprintf(usrdat, "%04X OR V%x, V%x", instr, x, y)
+#define X_C8_AND sprintf(usrdat, "%04X AND V%x, V%x", instr, x, y)
+#define X_C8_XOR sprintf(usrdat, "%04X XOR V%x, V%x", instr, x, y)
+#define X_C8_ADD sprintf(usrdat, "%04X ADD V%x, V%x", instr, x, y)
+#define X_C8_SUB sprintf(usrdat, "%04X SUB V%x, V%x", instr, x, y)
+#define X_C8_SHR sprintf(usrdat, "%04X SHR V%x, V%x", instr, x, y)
+#define X_C8_SUBN sprintf(usrdat, "%04X SUBN V%x, V%x", instr, x, y)
+#define X_C8_SHL sprintf(usrdat, "%04X SHL V%x, V%x", instr, x, y)
+#define X_C8_SNE sprintf(usrdat, "%04X SNE V%x, V%x", instr, x, y)
+#define X_C8_DRW sprintf(usrdat, "%04X DRW V%x, V%x, %d", instr, x, y, n)
c8_decode_generate(disasm)
diff --git a/sources/meta/exec.c b/sources/meta/exec.c
new file mode 100644
index 0000000..69e9a8a
--- /dev/null
+++ b/sources/meta/exec.c
@@ -0,0 +1,82 @@
+#define BEGIN \
+do{ \
+ chip8* c8 = usrdat; \
+ assert(c8);
+
+#define END }while(0)
+
+#define X_C8_ILL \
+BEGIN \
+ \
+ c8->running = false; \
+ report(ERR, "Illegal instruction (%04X) @ %04X\n", instr, offset); \
+END
+
+#define X_C8_CLS X_C8_ILL
+#define X_C8_RET X_C8_ILL
+#define X_C8_SYS X_C8_ILL
+
+#define X_C8_JP \
+BEGIN \
+ c8->pc = nnn - 2; \
+END
+
+#define X_C8_CALL X_C8_ILL
+#define X_C8_LDI X_C8_ILL
+#define X_C8_JPV X_C8_ILL
+
+#define X_C8_SEB \
+BEGIN \
+ if(c8->V[x] == kk) c8->pc += 2; \
+END
+
+#define X_C8_SNEB X_C8_ILL
+
+#define X_C8_LD \
+BEGIN \
+ c8->V[x] = kk; \
+END
+
+#define X_C8_ADDB \
+BEGIN \
+ int tmp = (int)c8->V[x] + (int)kk; \
+ c8->V[x] = tmp & 0xFF; \
+END
+
+#define X_C8_RND X_C8_ILL
+#define X_C8_SKP X_C8_ILL
+#define X_C8_SKNP X_C8_ILL
+#define X_C8_MVDT X_C8_ILL
+#define X_C8_LDK X_C8_ILL
+#define X_C8_LDDT X_C8_ILL
+#define X_C8_LDST X_C8_ILL
+#define X_C8_ADDI X_C8_ILL
+#define X_C8_HEX X_C8_ILL
+#define X_C8_BCD X_C8_ILL
+#define X_C8_SAVE X_C8_ILL
+#define X_C8_RESTORE X_C8_ILL
+#define X_C8_SE X_C8_ILL
+#define X_C8_MOVE X_C8_ILL
+#define X_C8_OR X_C8_ILL
+#define X_C8_AND X_C8_ILL
+#define X_C8_XOR X_C8_ILL
+
+#define X_C8_ADD \
+BEGIN \
+ int tmp = (int)c8->V[x] + (int)c8->V[y]; \
+ c8->V[0xf] = (tmp > 255); \
+ c8->V[x] = tmp & 0xFF; \
+END
+
+#define X_C8_SUB X_C8_ILL
+#define X_C8_SHR X_C8_ILL
+#define X_C8_SUBN X_C8_ILL
+#define X_C8_SHL X_C8_ILL
+#define X_C8_SNE X_C8_ILL
+#define X_C8_DRW X_C8_ILL
+
+c8_decode_generate(exec)
+
+#undef BEGIN
+#undef END
+#include "undef.c"