commit 9c994b3b9569b6dca35fcfd9f79da7edc332cc53
parent 40fccc47a931f670158243117e867fc1f9e34528
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 4 Apr 2012 22:58:22 -0700
disassmbly support
- utility routine to disassemble one instruction
- emulator disassembles the current instruction in state dump
- assembler includes disassembly in the output
Diffstat:
M | Makefile | | | 8 | ++++---- |
M | a16.c | | | 31 | +++++++++++++++++++++---------- |
M | dcpu.c | | | 14 | ++++++++++---- |
A | disassemble.c | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 124 insertions(+), 18 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,11 +1,11 @@
all: dcpu a16
-dcpu: dcpu.c
- gcc -Wall -o dcpu dcpu.c
+dcpu: dcpu.c disassemble.c
+ gcc -Wall -o dcpu dcpu.c disassemble.c
-a16: a16.c
- gcc -Wall -o a16 a16.c
+a16: a16.c disassemble.c
+ gcc -Wall -o a16 a16.c disassemble.c
clean:
rm -f dcpu a16
diff --git a/a16.c b/a16.c
@@ -41,6 +41,8 @@
typedef uint16_t u16;
typedef uint32_t u32;
+extern u16 *disassemble(u16 *pc, char *out);
+
static u16 image[65536] = { 0, };
static u16 PC = 0;
static FILE *fin;
@@ -151,10 +153,6 @@ static const char *tnames[] = {
",", "[", "]", ":", "+",
"<STRING>", "<NUMBER>", "<EOF>",
};
-static const char *rnames[] = {
- "A", "B", "C", "X", "Y", "Z", "I", "J",
-};
-
#define LASTKEYWORD tWORD
int _next(void) {
@@ -329,13 +327,24 @@ done:
void emit(const char *fn) {
FILE *fp;
- int n;
+ u16 *pc = image;
+ u16 *end = image + PC;
+ u16 *dis = pc;
filename = fn;
linenumber = 0;
fp = fopen(fn, "w");
if (!fp) die("cannot write file");
- for (n = 0; n < PC; n++)
- fprintf(fp, "%04x\n", image[n]);
+
+ while (pc < end) {
+ if (pc == dis) {
+ char out[128];
+ dis = disassemble(pc, out);
+ fprintf(fp, "%04x\t%04x:\t%s\n", *pc, (unsigned)(pc-image), out);
+ } else {
+ fprintf(fp, "%04x\n", *pc);
+ }
+ pc++;
+ }
fclose(fp);
}
@@ -359,9 +368,11 @@ int main(int argc, char **argv) {
assemble(argv[0]);
}
- linebuffer[0] = 0;
- resolve_fixups();
- emit(outfn);
+ if (PC != 0) {
+ linebuffer[0] = 0;
+ resolve_fixups();
+ emit(outfn);
+ }
return 0;
}
diff --git a/dcpu.c b/dcpu.c
@@ -40,6 +40,8 @@
typedef uint16_t u16;
typedef uint32_t u32;
+extern u16 *disassemble(u16 *pc, char *out);
+
struct dcpu {
u16 r[8];
u16 pc;
@@ -151,15 +153,19 @@ void dcpu_step(struct dcpu *d) {
void dumpheader(void) {
fprintf(stderr,
- "PC SP OV SKIP A B C X Y Z I J\n"
- "---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----\n");
+ "PC SP OV SKIP A B C X Y Z I J Instruction\n"
+ "---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -----------\n");
}
void dumpstate(struct dcpu *d) {
+ char out[128];
+ disassemble(d->m + d->pc, out);
fprintf(stderr,
- "%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
+ "%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %s\n",
d->pc, d->sp, d->ov, d->skip,
- d->r[0], d->r[1], d->r[2], d->r[3], d->r[4], d->r[5], d->r[6], d->r[7]);
+ d->r[0], d->r[1], d->r[2], d->r[3],
+ d->r[4], d->r[5], d->r[6], d->r[7],
+ out);
}
void load(struct dcpu *d, const char *fn) {
diff --git a/disassemble.c b/disassemble.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012, Brian Swetland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* A DCPU-16 Disassembler */
+
+/* DCPU-16 Spec is Copyright 2012 Mojang */
+/* http://0x10c.com/doc/dcpu-16.txt */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+typedef uint16_t u16;
+
+static const char *opcode[] = {
+ "XXX", "SET", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL",
+ "SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB",
+};
+static const char regs[8] = "ABCXYZIJ";
+
+static u16 *dis_operand(u16 *pc, u16 n, char *out) {
+ if (n < 0x08) {
+ sprintf(out,"%c",regs[n & 7]);
+ } else if (n < 0x10) {
+ sprintf(out,"[%c]",regs[n & 7]);
+ } else if (n < 0x18) {
+ sprintf(out,"[0x%04x+%c]",*pc++,regs[n & 7]);
+ } else if (n > 0x1f) {
+ sprintf(out,"%d", n - 0x20);
+ } else switch (n) {
+ case 0x18: strcpy(out,"POP"); break;
+ case 0x19: strcpy(out,"PEEK"); break;
+ case 0x1A: strcpy(out,"PUSH"); break;
+ case 0x1B: strcpy(out,"SP"); break;
+ case 0x1C: strcpy(out,"PC"); break;
+ case 0x1D: strcpy(out,"O"); break;
+ case 0x1e: sprintf(out,"[0x%04x]",*pc++); break;
+ case 0x1f: sprintf(out,"0x%04x",*pc++); break;
+ }
+ return pc;
+}
+u16 *disassemble(u16 *pc, char *out) {
+ u16 n = *pc++;
+ u16 op = n & 0xF;
+ u16 a = (n >> 4) & 0x3F;
+ u16 b = (n >> 10);
+ if (op > 0) {
+ sprintf(out,"%s ",opcode[op]);
+ pc = dis_operand(pc, a, out+strlen(out));
+ sprintf(out+strlen(out),", ");
+ pc = dis_operand(pc, b, out+strlen(out));
+ return pc;
+ }
+ if (a == 1) {
+ sprintf(out,"JSR ");
+ pc = dis_operand(pc, b, out+strlen(out));
+ return pc;
+ }
+ sprintf(out,"UNK[%02x] ", a);
+ pc = dis_operand(pc, b, out+strlen(out));
+ return pc;
+}
+