dcpu16

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

commit 261a2458d2047696e1309260e57edf5f4a2b7b17
parent 8edef0087c2720964f76c07576781811529b5eeb
Author: Brian Swetland <swetland@frotz.net>
Date:   Sat,  7 Apr 2012 16:15:15 -0700

a16: a number of shiny new features

- accept WORD, DAT, DATA, and DW for immediate data
- allow label: as well as :label to specify a label
- allow "quoted strings" in immediate data
- allow multiple (comma separated) values in a DATA statement
- allow [reg, imm] and [reg + imm] operand style
- don't try to disassemble constant data
- accept JMP b as an alias for SET PC, b
- accept MOV a, b as an alias for SET a, b
- prefer JMP and MOV in disassembly
- prefer [reg, imm] in disassembly
- TODO: option to request "classic" syntax in disassembly

Diffstat:
Massembler.c | 109++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mdisassemble.c | 9+++++++--
2 files changed, 96 insertions(+), 22 deletions(-)

diff --git a/assembler.c b/assembler.c @@ -39,12 +39,14 @@ #include <ctype.h> #include <getopt.h> +typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; extern u16 *disassemble(u16 *pc, char *out); static u16 image[65536] = { 0, }; +static u8 note[65536] = { 0, }; static u16 PC = 0; static FILE *fin; static const char *filename = ""; @@ -146,9 +148,10 @@ enum tokens { tSHR, tAND, tBOR, tXOR, tIFE, tIFN, tIFG, tIFB, tJSR, tPOP, tPEEK, tPUSH, tSP, tPC, tO, - tWORD, + tJMP, tMOV, + tDATA, tDAT, tDW, tWORD, tCOMMA, tOBRACK, tCBRACK, tCOLON, tPLUS, - tSTRING, tNUMBER, tEOF, + tSTRING, tQSTRING, tNUMBER, tEOF, }; static const char *tnames[] = { "A", "B", "C", "X", "Y", "Z", "I", "J", @@ -156,14 +159,15 @@ static const char *tnames[] = { "SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB", "JSR", "POP", "PEEK", "PUSH", "SP", "PC", "O", - "WORD", + "JMP", "MOV", + "DATA", "DAT", "DW", "WORD", ",", "[", "]", ":", "+", - "<STRING>", "<NUMBER>", "<EOF>", + "<STRING>", "<QUOTED-STRING>", "<NUMBER>", "<EOF>", }; #define LASTKEYWORD tWORD int _next(void) { - char c; + char c, *x; nextline: if (!*lineptr) { if (feof(fin)) return tEOF; @@ -182,6 +186,28 @@ nextline: case ']': return tCBRACK; case ':': return tCOLON; case '/': case ';': *lineptr = 0; goto nextline; + case '"': + x = tstring; + for (;;) { + switch((c = *lineptr++)) { + case 0: + die("unterminated string"); + case '"': + *x = 0; + return tQSTRING; + case '\\': + switch((c = *lineptr++)) { + case 'n': *x++ = '\n'; break; + case 't': *x++ = '\t'; break; + case 'r': *x++ = '\r'; break; + default: + *x++ = c; break; + } + break; + default: + *x++ = c; + } + } default: if (isdigit(c) || ((c == '-') && isdigit(*lineptr))) { tnumber = strtoul(lineptr-1, &lineptr, 0); @@ -189,7 +215,7 @@ nextline: } if (isalpha(c) || c == '_') { int n; - char *x = tstring; + x = tstring; lineptr--; while (isalnum(*lineptr) || *lineptr == '_') *x++ = tolower(*lineptr++); @@ -221,15 +247,26 @@ void expect(int t) { } void assemble_imm_or_label(void) { - next(); - if (token == tNUMBER) { - image[PC++] = tnumber; - } else if (token == tSTRING) { - image[PC] = 0; - use_label(tstring, PC++); - } else { - die("expected number or label"); - } + do { + next(); + if (token == tNUMBER) { + note[PC] = 'd'; + image[PC++] = tnumber; + } else if (token == tSTRING) { + note[PC] = 'd'; + image[PC] = 0; + use_label(tstring, PC++); + } else if (token == tQSTRING) { + char *x = tstring; + while (*x) { + note[PC] = 'd'; + image[PC++] = *x++; + } + } else { + die("expected number or label"); + } + next(); + } while (token == tCOMMA); } int assemble_operand(void) { @@ -262,9 +299,23 @@ int assemble_operand(void) { switch (token) { case tA: case tB: case tC: case tX: case tY: case tZ: case tI: case tJ: - n = 0x08 | (token & 7); + n = token & 7; + next(); + if (token == tCBRACK) + return 0x08 | n; + if ((token != tCOMMA) && (token != tPLUS)) + die("expected , or +"); + next(); + if (token == tSTRING) { + use_label(tstring, PC); + image[PC++] = 0; + } else if (token == tNUMBER) { + image[PC++] = tnumber; + } else { + die("expected immediate value"); + } expect(tCBRACK); - return n; + return 0x10 | n; case tSTRING: use_label(tstring, PC); case tNUMBER: @@ -291,7 +342,7 @@ int assemble_operand(void) { } void assemble_binop(int op) { - int pc = PC++; + u16 pc = PC++; int a, b; a = assemble_operand(); expect(tCOMMA); @@ -299,6 +350,11 @@ void assemble_binop(int op) { image[pc] = op | (a << 4) | (b << 10); } +void assemble_jump(void) { + u16 pc = PC++; + image[pc] = 0x01c1 | (assemble_operand() << 10); +} + void assemble(const char *fn) { u16 pc, n; fin = fopen(fn, "r"); @@ -308,16 +364,26 @@ void assemble(const char *fn) { for (;;) { next(); +again: switch (token) { case tEOF: goto done; + case tSTRING: + expect(tCOLON); + set_label(tstring, PC); + continue; case tCOLON: expect(tSTRING); set_label(tstring, PC); continue; - case tWORD: + case tWORD: case tDAT: case tDATA: case tDW: assemble_imm_or_label(); + goto again; + case tJMP: // alias for SET PC, ... + assemble_jump(); continue; + case tMOV: // alias for SET + token = tSET; case tSET: case tADD: case tSUB: case tMUL: case tDIV: case tMOD: case tSHL: case tSHR: case tAND: case tBOR: case tXOR: case tIFE: @@ -354,7 +420,10 @@ void emit(const char *fn, enum outformat format) { while (pc < end) { if (format == OUTFORMAT_PRETTY) { - if (pc == dis) { + if (note[pc-image] == 'd') { + fprintf(fp, "%04x\n", *pc); + dis = pc + 1; + } else if (pc == dis) { char out[128]; dis = disassemble(pc, out); fprintf(fp, "%04x\t%04x:\t%s\n", *pc, (unsigned)(pc-image), out); diff --git a/disassemble.c b/disassemble.c @@ -39,7 +39,7 @@ typedef uint16_t u16; static const char *opcode[] = { - "XXX", "SET", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL", + "XXX", "MOV", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL", "SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB", }; static const char regs[8] = "ABCXYZIJ"; @@ -50,7 +50,7 @@ static u16 *dis_operand(u16 *pc, u16 n, char *out) { } else if (n < 0x10) { sprintf(out,"[%c]",regs[n & 7]); } else if (n < 0x18) { - sprintf(out,"[0x%04x+%c]",*pc++,regs[n & 7]); + sprintf(out,"[%c, 0x%04x]",regs[n & 7], *pc++); } else if (n > 0x1f) { sprintf(out,"%d", n - 0x20); } else switch (n) { @@ -71,6 +71,11 @@ u16 *disassemble(u16 *pc, char *out) { u16 a = (n >> 4) & 0x3F; u16 b = (n >> 10); if (op > 0) { + if ((n & 0x03FF) == 0x1C1) { + sprintf(out,"JMP "); + pc = dis_operand(pc, b, out+strlen(out)); + return pc; + } sprintf(out,"%s ",opcode[op]); pc = dis_operand(pc, a, out+strlen(out)); sprintf(out+strlen(out),", ");