aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--make.c66
-rw-r--r--src/c8dump/main.c252
3 files changed, 319 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index fc16e29..99f41bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ compile_commands.json
# Compilation Output
ahoy
c8asm
+c8dump
!src/*
make
*.o
diff --git a/make.c b/make.c
index 8506903..4aa905d 100644
--- a/make.c
+++ b/make.c
@@ -52,6 +52,7 @@
static void build_ahoy(void);
static void build_c8asm(void);
+static void build_c8dump(void);
static void build_common(void);
static void build_librune(void);
static int globerr(const char *, int);
@@ -97,6 +98,7 @@ main(int argc, char **argv)
if (argc == 0) {
build_common();
+ build_c8dump();
build_c8asm();
build_ahoy();
} else if (streq(*argv, "clean")) {
@@ -306,6 +308,70 @@ out:
}
void
+build_c8dump(void)
+{
+ glob_t g;
+ char **objs;
+ cmd_t c = {0};
+ struct strv sv = {0};
+
+ build_librune();
+
+ if (glob("src/c8dump/*.c", 0, globerr, &g))
+ die("glob");
+
+ objs = bufalloc(nullptr, g.gl_pathc, sizeof(*objs));
+ for (size_t i = 0; i < g.gl_pathc; i++) {
+ char *s = strdup(g.gl_pathv[i]);
+ if (!s)
+ die("strdup");
+ s[strlen(s) - 1] = 'o';
+ objs[i] = s;
+ }
+
+ env_or_default(&sv, "CC", CC);
+ if (FLAGSET('r'))
+ env_or_default(&sv, "CFLAGS", CFLAGS_RLS);
+ else
+ env_or_default(&sv, "CFLAGS", CFLAGS_DBG);
+
+ for (size_t i = 0; i < g.gl_pathc; i++) {
+ if (!FLAGSET('f') && !foutdated(objs[i], g.gl_pathv[i]))
+ continue;
+
+ c.dst = objs[i];
+ cmdaddv(&c, sv.buf, sv.len);
+ if (FLAGSET('l'))
+ cmdadd(&c, "-flto");
+ cmdadd(&c, "-Isrc/common", "-Ivendor/da", "-Ivendor/librune/include");
+ cmdadd(&c, "-c", g.gl_pathv[i], "-o", objs[i]);
+ CMDPRC2(c);
+ }
+
+ if (!FLAGSET('f') && !foutdatedv("c8dump", (const char **)objs, g.gl_pathc))
+ goto out;
+
+ strvfree(&sv);
+ env_or_default(&sv, "CC", CC);
+ env_or_default(&sv, "LDFLAGS", nullptr);
+
+ c.dst = "c8dump";
+ cmdaddv(&c, sv.buf, sv.len);
+ if (FLAGSET('l'))
+ cmdadd(&c, "-flto");
+ cmdadd(&c, "-o", c.dst);
+ cmdaddv(&c, objs, g.gl_pathc);
+ cmdadd(&c, "src/common/cerr.o", "vendor/librune/librune.a");
+ CMDPRC2(c);
+
+out:
+ globfree(&g);
+ strvfree(&sv);
+ for (size_t i = 0; i < g.gl_pathc; i++)
+ free(objs[i]);
+}
+
+void
build_librune(void)
{
cmd_t c = {0};
diff --git a/src/c8dump/main.c b/src/c8dump/main.c
new file mode 100644
index 0000000..c9e429b
--- /dev/null
+++ b/src/c8dump/main.c
@@ -0,0 +1,252 @@
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <builder.h>
+
+#include "cerr.h"
+#include "macros.h"
+
+#define MEM_RESERVED 0x200
+#define MEM_TOTAL 0xFFF
+#define LABEL_BUFSIZ (sizeof("label_4095"))
+
+static void dumpfile(int, const char *);
+static const char *getlabel(uint16_t);
+
+static uint16_t labelsfxs[MEM_TOTAL - MEM_RESERVED + 1];
+
+int
+main(int argc, char **argv)
+{
+ int opt;
+ const struct option longopts[] = {
+ {"help", no_argument, nullptr, 'h'},
+ {nullptr, no_argument, nullptr, 0 },
+ };
+
+ cerrinit(*argv);
+ while ((opt = getopt_long(argc, argv, "h", longopts, nullptr)) != -1) {
+ switch (opt) {
+ case 'h':
+ execlp("man", "man", "1", argv[0], nullptr);
+ die("execlp: man 1 %s", argv[0]);
+ default:
+ fprintf(stderr,
+ "Usage: %s [file ...]\n"
+ " %s -h\n",
+ argv[0], argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (!argc)
+ dumpfile(STDIN_FILENO, "-");
+ for (int i = 0; i < argc; i++) {
+ if (streq("-", argv[i]))
+ dumpfile(STDIN_FILENO, "-");
+ else {
+ int fd;
+ if ((fd = open(argv[i], O_RDONLY)) == -1)
+ die("open: %s", argv[i]);
+ dumpfile(fd, argv[i]);
+ close(fd);
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+void
+dumpfile(int fd, const char *filename)
+{
+ char *buf;
+ size_t blksize;
+ ssize_t nr;
+ struct stat st;
+ struct u8str sb;
+
+ if (fstat(fd, &st) == -1)
+ die("fstat: %s", filename);
+ blksize = MAX(st.st_blksize, BUFSIZ);
+ if (!(buf = malloc(blksize)))
+ die("malloc");
+
+ /* Load the contents of the file into sb */
+ u8strinit(&sb, S_ISREG(st.st_mode) ? (size_t)st.st_size : blksize);
+ while ((nr = read(fd, buf, blksize)) > 0) {
+ struct u8view v = {
+ .p = buf,
+ .len = nr,
+ };
+ if (!u8strpush(&sb, v))
+ die("u8strpush");
+ }
+ if (nr == -1)
+ die("read: %s", filename);
+
+ free(buf);
+
+ if (sb.len & 1) {
+ diex("%s: binary size (%zu B) is odd; missing padding bytes?", filename,
+ sb.len);
+ }
+
+ for (size_t i = 0, j = 0; i < sb.len; i += 2) {
+ uint16_t op = (sb.p[i] << 8) | sb.p[i + 1];
+ switch (op >> 12) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0xA:
+ case 0xB:;
+ uint16_t addr = op & 0xFFF;
+ if (op != 0x00E0 && op != 0x00EE && addr >= MEM_RESERVED
+ && !labelsfxs[addr - MEM_RESERVED])
+ {
+ labelsfxs[addr - MEM_RESERVED] = ++j;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < sb.len; i += 2) {
+ uint16_t op = (sb.p[i] << 8) | sb.p[i + 1];
+ static bool indent;
+
+ if (i < lengthof(labelsfxs) && labelsfxs[i]) {
+ printf("%s:\n", getlabel(i + MEM_RESERVED));
+ indent = true;
+ }
+ if (indent)
+ putchar('\t');
+
+ switch (op >> 12) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0xA:
+ case 0xB:;
+ static const char *ops_1[] = {
+ [0x0] = "sys", [0x1] = "jp", [0x2] = "call",
+ [0xA] = "ld i", [0xB] = "jp v0",
+ };
+ if (op == 0x00E0)
+ puts("cls");
+ else if (op == 0x00EE)
+ puts("ret");
+ else
+ printf("%s %s\n", ops_1[op >> 12], getlabel(op & 0xFFF));
+ break;
+
+ case 0x3:
+ case 0x4:
+ case 0x6:
+ case 0x7:
+ case 0xC:;
+ static const char *ops_2[] = {
+ [0x3] = "se", [0x4] = "sne", [0x6] = "ld",
+ [0x7] = "add", [0xC] = "rnd",
+ };
+ printf("%s v%x 0x%02X\n", ops_2[op >> 12], (op >> 8) & 0xF,
+ op & 0xFF);
+ break;
+
+ case 0x5:
+ case 0x8:
+ case 0x9:
+ case 0xD:;
+ uint8_t n1, n2, n3, n4, i;
+ static const char *ops_3[0xFF + 1] = {
+ [0x50] = "se", [0x80] = "ld", [0x81] = "or", [0x82] = "and",
+ [0x83] = "xor", [0x84] = "add", [0x85] = "sub", [0x86] = "shr",
+ [0x87] = "subn", [0x8E] = "shl", [0x90] = "sne",
+ };
+
+ n1 = op >> 12;
+ n2 = (op >> 8) & 0xF;
+ n3 = (op >> 4) & 0xF;
+ n4 = (op >> 0) & 0xF;
+ i = (n1 << 4) | n4;
+
+ if (n1 == 0xD)
+ printf("drw v%x v%x %u\n", n2, n3, n4);
+ else if (!ops_3[i])
+ goto print_bytes;
+ else {
+ printf(n4 == 0x6 || n4 == 0xE ? "%s v%x\n" : "%s v%x v%x\n",
+ ops_3[i], n2, n3);
+ }
+ break;
+
+ case 0xE:
+ if (op & 0xFF != 0x9E)
+ goto print_bytes;
+ printf("skp v%x\n", (op >> 12) & 0xF);
+ break;
+
+ case 0xF:;
+ uint8_t x = (op >> 8) & 0xF;
+ switch (op & 0xFF) {
+ case 0x07:
+ printf("ld v%x dt\n", x);
+ break;
+ case 0x0A:
+ printf("ld v%x k\n", x);
+ break;
+ case 0x15:
+ printf("ld dt v%x\n", x);
+ break;
+ case 0x18:
+ printf("ld st v%x\n", x);
+ break;
+ case 0x1E:
+ printf("add i v%x\n", x);
+ break;
+ case 0x29:
+ printf("hex v%x\n", x);
+ break;
+ case 0x33:
+ printf("bcd v%x\n", x);
+ break;
+ case 0x55:
+ printf("stor v%x\n", x);
+ break;
+ case 0x65:
+ printf("rstr v%x\n", x);
+ break;
+ default:
+ goto print_bytes;
+ }
+ break;
+
+ default:
+print_bytes:
+ printf("db 0x%02X\n%sdb 0x%02X\n", op >> 8, indent ? "\t" : "",
+ op & 0xFF);
+ }
+ }
+
+ u8strfree(sb);
+}
+
+const char *
+getlabel(uint16_t addr)
+{
+ static char buf[LABEL_BUFSIZ + 69];
+ if (addr < MEM_RESERVED)
+ snprintf(buf, sizeof(buf), "0x%03X", addr);
+ else {
+ snprintf(buf, sizeof(buf), "label_%" PRIu16,
+ labelsfxs[addr - MEM_RESERVED]);
+ }
+ return buf;
+}