From 15f549712814d7f9165675c244785d688a8c06f6 Mon Sep 17 00:00:00 2001 From: Vyacheslav Barinov Date: Fri, 6 Apr 2012 08:32:09 +0400 Subject: [PATCH 1/9] Can use () instead of [] as Notch shows in http://i.imgur.com/XIXc4.jpg I do know that this solution is not nice but adding new class of brackets will cause too much refactoring. So [A) and (A] work too =) --- assembler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assembler.c b/assembler.c index 67d5440..364f7bb 100644 --- a/assembler.c +++ b/assembler.c @@ -171,8 +171,8 @@ int _next(void) { switch ((c = *lineptr++)) { case ',': return tCOMMA; case '+': return tPLUS; - case '[': return tOBRACK; - case ']': return tCBRACK; + case '[': case '(': return tOBRACK; + case ']': case ')': return tCBRACK; case ':': return tCOLON; case '/': case ';': *lineptr = 0; goto nextline; default: From b076c41c844ae005a7b6d9d91776c151c04027c0 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 15:58:16 +0800 Subject: [PATCH 2/9] Add screen dumping & hello world test --- emulator.c | 45 +++++++++++++++++++++++++++++++++++++-------- tests/helloworld.dc | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 tests/helloworld.dc diff --git a/emulator.c b/emulator.c index e5b1ec4..8f0c56e 100644 --- a/emulator.c +++ b/emulator.c @@ -37,6 +37,10 @@ #include #include +#define SCREEN_REGION (0x8000) +#define SCREEN_WIDTH (36) +#define SCREEN_HEIGHT (12) + typedef uint16_t u16; typedef uint32_t u32; @@ -90,7 +94,7 @@ u16 *dcpu_opr(struct dcpu *d, u16 code) { } } -void dcpu_step(struct dcpu *d) { +int dcpu_step(struct dcpu *d) { u16 op = d->m[d->pc++]; u16 dst; u32 res; @@ -106,10 +110,10 @@ void dcpu_step(struct dcpu *d) { d->m[--(d->sp)] = d->pc; d->pc = a; } - return; + return 1; default: fprintf(stderr, "< ILLEGAL OPCODE >\n"); - exit(0); + return 0; } } @@ -137,7 +141,7 @@ void dcpu_step(struct dcpu *d) { if (d->skip) { d->skip = 0; - return; + return 1; } switch (op & 0xF) { @@ -149,6 +153,7 @@ void dcpu_step(struct dcpu *d) { case 0xC: case 0xD: case 0xE: case 0xF: d->skip = !res; } + return 1; } void dumpheader(void) { @@ -157,6 +162,27 @@ void dumpheader(void) { "---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -----------\n"); } +void dumpboxhl(void) { + fputc('+', stderr); + for (int i = SCREEN_WIDTH; i--;) + fputc('-', stderr); + fprintf(stderr, "+\n"); +} + +void dumpscreen(struct dcpu *d) { + dumpboxhl(); + for (int y = 0; y < SCREEN_HEIGHT; y++) { + fputc('|', stderr); + for (int x = 0; x < SCREEN_WIDTH; x++) { + u16 c = d->m[SCREEN_REGION + (y * SCREEN_WIDTH) + x]; + c = c & 0xff; + fputc(isprint(c) ? c : ' ', stderr); + } + fprintf(stderr, "|\n"); + } + dumpboxhl(); +} + void dumpstate(struct dcpu *d) { char out[128]; disassemble(d->m + d->pc, out); @@ -192,10 +218,13 @@ int main(int argc, char **argv) { load(&d, argc > 1 ? argv[1] : "out.hex"); dumpheader(); - for (;;) { - dumpstate(&d); - dcpu_step(&d); - } + do { + //dumpscreen(&d); + dumpstate(&d); + } while (dcpu_step(&d)); + + dumpscreen(&d); + return 0; } diff --git a/tests/helloworld.dc b/tests/helloworld.dc new file mode 100644 index 0000000..15d19bb --- /dev/null +++ b/tests/helloworld.dc @@ -0,0 +1,42 @@ +; Try some basic stuff + SET A, 0x30 ; 7c01 0030 + SET [0x1000], 0x20 ; 7de1 1000 0020 + SUB A, [0x1000] ; 7803 1000 + IFN A, 0x10 ; c00d + SET PC, crash ; 7dc1 001a [*] + +; Do a loopy thing + SET I, 10 ; a861 + SET A, 0x2000 ; 7c01 2000 +:loop SET [0x2000+I], [A] ; 2161 2000 + SUB I, 1 ; 8463 + IFN I, 0 ; 806d + SET PC, loop ; 7dc1 000d [*] + +; Call a subroutine + SET X, 0x4 ; 9031 + JSR testsub ; 7c10 0018 [*] + SET PC, print ; 7dc1 001a [*] + +:testsub SHL X, 4 ; 9037 + SET PC, POP ; 61c1 + +; "Hello, world!" +; Set 0x8000 - 0x8180 to an ASCII value to output to console +:print + SET [0x8000], 72 + SET [0x8001], 101 + SET [0x8002], 108 + SET [0x8003], 108 + SET [0x8004], 111 + SET [0x8005], 44 + SET [0x8006], 32 + SET [0x8007], 119 + SET [0x8008], 111 + SET [0x8009], 114 + SET [0x800a], 108 + SET [0x800b], 100 + SET [0x800c], 33 + +:crash + WORD 0xeee0 From 5ef2f440ac6779c37491391b0ff0cd6caf505acc Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 16:17:35 +0800 Subject: [PATCH 3/9] Add support for `DAT [, ]` instruction Seen in Notches latest screenshot http://i.imgur.com/Tq9ue.jpg Note that colour printing in the program output does not work yet but the facility is there. --- assembler.c | 61 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/assembler.c b/assembler.c index 67d5440..2332d52 100644 --- a/assembler.c +++ b/assembler.c @@ -138,26 +138,25 @@ enum tokens { tXXX, tSET, tADD, tSUB, tMUL, tDIV, tMOD, tSHL, tSHR, tAND, tBOR, tXOR, tIFE, tIFN, tIFG, tIFB, tJSR, - tPOP, tPEEK, tPUSH, tSP, tPC, tO, + tPOP, tPEEK, tPUSH, tSP, tPC, tO, tDAT, tWORD, - tCOMMA, tOBRACK, tCBRACK, tCOLON, tPLUS, - tSTRING, tNUMBER, tEOF, + tCOMMA, tOBRACK, tCBRACK, tCOLON, tPLUS, tQUOTE, + tSTRING, tDATA, tNUMBER, tEOL, 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", + "POP", "PEEK", "PUSH", "SP", "PC", "O", "DAT", "WORD", - ",", "[", "]", ":", "+", - "", "", "", + ",", "[", "]", ":", "+", "\"", + "", "", "", "", "", }; #define LASTKEYWORD tWORD int _next(void) { char c; -nextline: if (!*lineptr) { if (feof(fin)) return tEOF; if (fgets(linebuffer, 128, fin) == 0) return tEOF; @@ -165,7 +164,7 @@ int _next(void) { linenumber++; } while (*lineptr <= ' ') { - if (*lineptr == 0) goto nextline; + if (*lineptr == 0) return tEOL; lineptr++; } switch ((c = *lineptr++)) { @@ -173,8 +172,9 @@ int _next(void) { case '+': return tPLUS; case '[': return tOBRACK; case ']': return tCBRACK; + case '"': return tQUOTE; case ':': return tCOLON; - case '/': case ';': *lineptr = 0; goto nextline; + case '/': case ';': *lineptr = 0; return tEOL; default: if (isdigit(c) || ((c == '-') && isdigit(*lineptr))) { tnumber = strtoul(lineptr-1, &lineptr, 0); @@ -225,6 +225,44 @@ void assemble_imm_or_label(void) { } } +void assemble_data(void) { + int argc = -1; +nextarg: + argc++; + next(); + + if (argc % 2) { + if (token == tEOL) return; + if (token == tCOMMA) goto nextarg; + die("expected comma or newline"); + } + + /* 0x0000 */ + if (token == tNUMBER) + image[PC++] = tnumber; + + else if (token == tQUOTE) { + /* "literal \"strings\" with \n escape chars" */ + while (*lineptr) { + char c = *lineptr++; + if (!isascii(c)) + die("illegal character '%c'", c); + + if (c == '"') + goto nextarg; + + if (c == '\\' && (iscntrl(*lineptr) || *lineptr == '\\' || *lineptr == '"')) + c = *lineptr++; + + image[PC++] = (u16)c; + } + } else { + die("expecting or , found %s", tnames[token]); + } + + goto nextarg; +} + int assemble_operand(void) { u16 n; next(); @@ -304,10 +342,15 @@ void assemble(const char *fn) { switch (token) { case tEOF: goto done; + case tEOL: + continue; case tCOLON: expect(tSTRING); set_label(tstring, PC); continue; + case tDAT: + assemble_data(); + continue; case tWORD: assemble_imm_or_label(); continue; From 454ad859a12620fd9050d184cb34d8caa32f46e8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 16:07:26 +0800 Subject: [PATCH 4/9] Use .dc extension for DCPU-16 asm files --- tests/{example.s => example.dc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{example.s => example.dc} (100%) diff --git a/tests/example.s b/tests/example.dc similarity index 100% rename from tests/example.s rename to tests/example.dc From 5a246f5bac27228a336d43e530cfd7e6aad93c65 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 16:30:36 +0800 Subject: [PATCH 5/9] Missing #include for strcasecmp --- assembler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/assembler.c b/assembler.c index 2332d52..b9f5ae4 100644 --- a/assembler.c +++ b/assembler.c @@ -37,6 +37,7 @@ #include #include #include +#include typedef uint16_t u16; typedef uint32_t u32; From d81382a7b6b93105b84bdb27f5696805dc933478 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 17:00:59 +0800 Subject: [PATCH 6/9] Add unescape function & remove non-standard isascii usage --- assembler.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/assembler.c b/assembler.c index b9f5ae4..c18ab86 100644 --- a/assembler.c +++ b/assembler.c @@ -226,6 +226,17 @@ void assemble_imm_or_label(void) { } } +char unescape(char c) { + switch (c) { + case '\\': case '"': return c; + case '0': return 0x00; case 'b': return 0x08; + case 't': return 0x09; case 'n': return 0x0a; + case 'r': return 0x0d; case 'e': return 0x1b; + default: die("unknown escape sequence: \\%c", c); + } + return 0; +} + void assemble_data(void) { int argc = -1; nextarg: @@ -246,15 +257,10 @@ void assemble_data(void) { /* "literal \"strings\" with \n escape chars" */ while (*lineptr) { char c = *lineptr++; - if (!isascii(c)) - die("illegal character '%c'", c); - - if (c == '"') - goto nextarg; - - if (c == '\\' && (iscntrl(*lineptr) || *lineptr == '\\' || *lineptr == '"')) - c = *lineptr++; - + if (c == '"') goto nextarg; + /* check for escaped characters */ + if (c == '\\') + c = unescape(*lineptr++); image[PC++] = (u16)c; } } else { From fd261931e07112b3f800aab9bd2e3a250fd159e1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 17:01:45 +0800 Subject: [PATCH 7/9] Allow custom compilers in makefile with `CC=clang make` --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d811943..df7d113 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,14 @@ +CFLAGS := -std=c99 -Wall -Wextra +CC ?= gcc + all: dcpu a16 dcpu: emulator.c disassemble.c - gcc -Wall -o dcpu emulator.c disassemble.c + $(CC) $(CFLAGS) -o $@ emulator.c disassemble.c a16: assembler.c disassemble.c - gcc -Wall -o a16 assembler.c disassemble.c + $(CC) $(CFLAGS) -o $@ assembler.c disassemble.c clean: rm -f dcpu a16 From 1c8fff3b31cd0585d9951e40ba6c3d42c80f7e67 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 17:03:15 +0800 Subject: [PATCH 8/9] Add colour output DCPU-16 example code Note however terminal colour output isn't finished. --- tests/colours.dc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/colours.dc diff --git a/tests/colours.dc b/tests/colours.dc new file mode 100644 index 0000000..350de55 --- /dev/null +++ b/tests/colours.dc @@ -0,0 +1,41 @@ +; Notch's second "hello word" program. +; http://i.imgur.com/XIXc4.jpg +; Supposed to show formatting. +:start + set i, 0 + set j, 0 + set b, 0xf100 + +:nextchar + set a, [data+i] + ife a, 0 + set PC, end + ifg a, 0xff + set PC, setcolor + bor a, b + set [0x8000+j], a + add i, 1 + add j, 1 + set PC, nextchar + +:setcolor + set b, a + and b, 0xff + shl b, 8 + ifg a, 0x1ff + add b, 0x80 ; Add high bit to each character we color. So the character must be 7-bit ASCII + add i, 1 + set PC, nextchar + +:data + dat 0x170, "Hello ", 0x2e1, "world", 0x170, ", how are you?", 0 + ; Color format: + ; After processing: + ; 0x170 -> b = 0x7000 -> 0111 0000 0XXX XXXX = white(grey) on black + ; 0x2e1 -> b = 0xe180 -> 1110 0001 1XXX XXXX = yellow on blue + ; b gets OR'd with each character. + ; ANSI says: black is 0, white is 7, yellow is 3, blue is 4 + ; If black is 0 and grey is 7, it's or +:end + ;set PC, start + WORD 0xeee0 From 9fe7e9a698d74dfb7cf4384ee4c1bad90ab7b6e0 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 6 Apr 2012 17:15:00 +0800 Subject: [PATCH 9/9] Silence compiler errors --- assembler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/assembler.c b/assembler.c index 83786b2..49c0415 100644 --- a/assembler.c +++ b/assembler.c @@ -425,6 +425,7 @@ void emit(const char *fn, enum outformat format) { static void usage(int argc, char **argv) { + (void) argc; fprintf(stderr, "usage: %s [-o output] [-O output_format] \n", argv[0]); fprintf(stderr, "\toutput_format can be one of: pretty, hex, binary\n"); }