dcpu16

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 1612c0df3b7ee10d3509f418d89eacdf701d8a39
parent 1f94d81ac4f15028210db0cf396cdc7ebe3c186e
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed,  4 Apr 2012 19:35:18 -0700

a16: an assmbler for the DCPU-16

Work in progress.  Support for labels is the next todo.

Diffstat:
MMakefile | 7++++++-
Aa16.c | 245+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 251 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,11 @@ +all: dcpu a16 + dcpu: dcpu.c gcc -Wall -o dcpu dcpu.c +a16: a16.c + gcc -Wall -o a16 a16.c + clean: - rm -f dcpu + rm -f dcpu a16 diff --git a/a16.c b/a16.c @@ -0,0 +1,245 @@ +/* Copyright 2012, Brian Swetland. BSD Licensed. Share and Enjoy! */ +/* A DCPU-16 Assembler */ + +/* DCPU-16 Spec is Copyright 2012 Mojang */ +/* http://0x10c.com/doc/dcpu-16.txt */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +typedef uint16_t u16; +typedef uint32_t u32; + +static u16 image[65536] = { 0, }; +static u16 PC = 0; +static FILE *fin; +static const char *filename = ""; +static int linenumber = 0; + +static char linebuffer[128] = { 0, }; +static char *lineptr = linebuffer; +static int token; +static char tstring[128]; +static u16 tnumber; + +void die(const char *fmt, ...) { + va_list ap; + fprintf(stderr,"%s:%d: ", filename, linenumber); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr,"\n"); + if (linebuffer[0]) + fprintf(stderr,"%s:%d: >> %s <<\n", filename, linenumber, linebuffer); + exit(1); +} + +enum tokens { + tA, tB, tC, tX, tY, tZ, tI, tJ, + tXXX, tSET, tADD, tSUB, tMUL, tDIV, tMOD, tSHL, + tSHR, tAND, tBOR, tXOR, tIFE, tIFN, tIFG, tIFB, + tJSR, + tPOP, tPEEK, tPUSH, tSP, tPC, tO, + tCOMMA, tOBRACK, tCBRACK, tCOLON, + tSTRING, tNUMBER, tEOF, +}; +static const char *tnames[] = { + "A", "B", "C", "X", "Y", "Z", "I", "J", + "XXX", "SET", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL", + "SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB", + "JSR", + "POP", "PEEK", "PUSH", "SP", "PC", "O", + ",", "[", "]", ":", + "<STRING>", "<NUMBER>", "<EOF>", +}; +static const char *rnames[] = { + "A", "B", "C", "X", "Y", "Z", "I", "J", +}; + +#define LASTKEYWORD tO + +int _next(void) { + char c; +nextline: + if (!*lineptr) { + if (feof(fin)) return tEOF; + if (fgets(linebuffer, 128, fin) == 0) return tEOF; + lineptr = linebuffer; + linenumber++; + } + while (*lineptr <= ' ') { + if (*lineptr == 0) goto nextline; + lineptr++; + } + switch ((c = *lineptr++)) { + case ',': return tCOMMA; + case '[': return tOBRACK; + case ']': return tCBRACK; + case ':': return tCOLON; + case '/': case ';': *lineptr = 0; goto nextline; + default: + if (isdigit(c) || + (((c == '+') || (c == '-')) && isdigit(*lineptr))) { + tnumber = strtoul(lineptr-1, &lineptr, 0); + return tNUMBER; + } + if (isalpha(c)) { + int n; + char *x = tstring; + lineptr--; + while (isalnum(*lineptr)) + *x++ = tolower(*lineptr++); + *x = 0; + for (n = 0; n <= LASTKEYWORD; n++) + if (!strcasecmp(tnames[n], tstring)) + return n; + return tSTRING; + } + die("illegal character '%c'", c); + return tEOF; + } +} + +int next(void) { + token = _next(); + //fprintf(stderr,"%3d %s\n", token, tnames[token]); + return token; +} + +void expect(int t) { + if (next() != t) + die("expecting %s, found %s", tnames[t], tnames[token]); +} + +int assemble_operand(void) { + int n; + next(); + switch (token) { + case tA: case tB: case tC: case tX: + case tY: case tZ: case tI: case tJ: + return token & 7; + case tPOP: return 0x18; + case tPEEK: return 0x19; + case tPUSH: return 0x1a; + case tSP: return 0x1b; + case tPC: return 0x1c; + case tO: return 0x1d; + case tNUMBER: + image[PC++] = tnumber; + return 0x1f; + default: + if (token != tOBRACK) + die("expected ["); + } + next(); + switch (token) { + case tA: case tB: case tC: case tX: + case tY: case tZ: case tI: case tJ: + n = token & 7; + next(); + if (token == tCBRACK) { + return n | 0x08; + } else if (token == tCOMMA) { + expect(tNUMBER); // handle labels + image[PC++] = tnumber; + expect(tCBRACK); + return n | 0x10; + } else { + die("invalid operand"); + } + //case tSTRING: + // handle labels + case tNUMBER: + image[PC++] = tnumber; + next(); + if (token == tCBRACK) { + return 0x1e; + } else if ((token >= tA) && (token <= tJ)) { + return 0x10 | (token & 7); + } else { + die("invalid operand"); + } + default: + die("invalid operand"); + } + return 0; +} + +void assemble_binop(int op) { + int pc = PC++; + int a, b; + a = assemble_operand(); + expect(tCOMMA); + b = assemble_operand(); + image[pc] = op | (a << 4) | (b << 10); +} + +void assemble(const char *fn) { + fin = fopen(fn, "r"); + filename = fn; + linenumber = 0; + if (!fin) die("cannot read file"); + + for (;;) { + next(); + switch (token) { + case tEOF: + goto done; + case tCOLON: + expect(tSTRING); + //setlabel(tstring, PC); + continue; + case tSET: case tADD: case tSUB: case tMUL: + case tDIV: case tMOD: case tSHL: case tSHR: + case tAND: case tBOR: case tXOR: case tIFE: + case tIFN: case tIFG: case tIFB: + assemble_binop(token - tXXX); + continue; + default: + die("unexpected: %s", tnames[token]); + } + } +done: + fclose(fin); +} + +void emit(const char *fn) { + FILE *fp; + int n; + 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]); + fclose(fp); +} + +int main(int argc, char **argv) { + const char *outfn = "out.hex"; + + while (argc > 1) { + argc--; + argv++; + if (argv[0][0] == '-') { + if (!strcmp(argv[0],"-o")) { + if (argc > 1) { + outfn = argv[1]; + argc--; + argv++; + continue; + } + } + die("unknown option: %s", argv[0]); + } + assemble(argv[0]); + } + + emit(outfn); + return 0; +} +