Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can use () instead of [] as Notch shows in http://i.imgur.com/XIXc4.jpg #6

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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
73 changes: 62 additions & 11 deletions assembler.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <strings.h>
#include <getopt.h>

typedef uint16_t u16;
Expand Down Expand Up @@ -145,43 +146,43 @@ 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",
",", "[", "]", ":", "+",
"<STRING>", "<NUMBER>", "<EOF>",
",", "[", "]", ":", "+", "\"",
"<STRING>", "<DATA>", "<NUMBER>", "<EOL>", "<EOF>",
};
#define LASTKEYWORD tWORD

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;
if (*lineptr == 0) return tEOL;
lineptr++;
}
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 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);
Expand Down Expand Up @@ -232,6 +233,50 @@ 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:
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 (c == '"') goto nextarg;
/* check for escaped characters */
if (c == '\\')
c = unescape(*lineptr++);
image[PC++] = (u16)c;
}
} else {
die("expecting <NUMBER> or <DATA>, found %s", tnames[token]);
}

goto nextarg;
}

int assemble_operand(void) {
u16 n;
next();
Expand Down Expand Up @@ -311,10 +356,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;
Expand Down Expand Up @@ -375,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] <input file(s)>\n", argv[0]);
fprintf(stderr, "\toutput_format can be one of: pretty, hex, binary\n");
}
Expand Down
53 changes: 41 additions & 12 deletions emulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#include <string.h>
#include <ctype.h>

#define SCREEN_REGION (0x8000)
#define SCREEN_WIDTH (36)
#define SCREEN_HEIGHT (12)

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
Expand Down Expand Up @@ -104,7 +108,7 @@ void dcpu_skip(struct dcpu *d) {
d->pc += skiptable[(op >> 4) & 31];
}

void dcpu_step(struct dcpu *d) {
int dcpu_step(struct dcpu *d) {
u16 op = d->m[d->pc++];
u16 dst;
u32 res;
Expand All @@ -128,26 +132,27 @@ void dcpu_step(struct dcpu *d) {
case 0x9: res = a & b; break;
case 0xA: res = a | b; break;
case 0xB: res = a ^ b; break;
case 0xC: if (a!=b) dcpu_skip(d); return;
case 0xD: if (a==b) dcpu_skip(d); return;
case 0xE: if (a<=b) dcpu_skip(d); return;
case 0xF: if ((a&b)==0) dcpu_skip(d); return;
case 0xC: if (a!=b) dcpu_skip(d); return 1;
case 0xD: if (a==b) dcpu_skip(d); return 1;
case 0xE: if (a<=b) dcpu_skip(d); return 1;
case 0xF: if ((a&b)==0) dcpu_skip(d); return 1;
}

if (dst < 0x1f) *aa = res;
return;
return 1;

extended:
a = *dcpu_opr(d, op >> 10);
switch ((op >> 4) & 0x3F) {
case 0x01:
d->m[--(d->sp)] = d->pc;
d->pc = a;
return;
return 1;
default:
fprintf(stderr, "< ILLEGAL OPCODE >\n");
exit(0);
return 0;
}
return 1;
}

void dumpheader(void) {
Expand All @@ -156,6 +161,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);
Expand Down Expand Up @@ -191,10 +217,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;
}

41 changes: 41 additions & 0 deletions tests/colours.dc
Original file line number Diff line number Diff line change
@@ -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 <FORE> <BACK> <EXTRA BIT> or <FORE> <EXTRA BIT> <BACK>
:end
;set PC, start
WORD 0xeee0
File renamed without changes.
42 changes: 42 additions & 0 deletions tests/helloworld.dc
Original file line number Diff line number Diff line change
@@ -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