Skip to content
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ cscope.out
*.bin
*.hex
*.o
a16
dcpu
44 changes: 36 additions & 8 deletions assembler.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ enum outformat {
OUTFORMAT_PRETTY,
OUTFORMAT_HEX,
OUTFORMAT_BINARY,
OUTFORMAT_C,
};

void die(const char *fmt, ...) {
Expand Down Expand Up @@ -149,7 +150,9 @@ enum tokens {
tR0, tR1, tR2, tR3, tR4, tR5, tR6, tR7,
tSET, tADD, tSUB, tMUL, tDIV, tMOD, tSHL,
tSHR, tAND, tBOR, tXOR, tIFE, tIFN, tIFG, tIFB,
tJSR,
tJSR, tR8, tR9, tR10, tR11, tR12, tR13, tINT,
tIAG, tIAS, tRFI, tIAQ, tR14, tR15, tR16,
tHWN, tHWQ, tHWI,
tPOP, tPEEK, tPUSH, tSP, tPC, tO,
tJMP, tMOV, tNOP,
tDATA, tDAT, tDW, tWORD,
Expand All @@ -161,7 +164,9 @@ static const char *tnames[] = {
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
"SET", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL",
"SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB",
"JSR",
"JSR", "R8", "R9", "R10", "R11", "R12", "R13", "INT",
"IAG", "IAS", "RFI", "IAQ", "R14", "R15", "R16",
"HWN", "HWQ", "HWI",
"POP", "PEEK", "PUSH", "SP", "PC", "O",
"JMP", "MOV", "NOP",
"DATA", "DAT", "DW", "WORD",
Expand Down Expand Up @@ -275,7 +280,7 @@ void assemble_imm_or_label(void) {
}

int assemble_operand(void) {
u16 n;
u16 n = 0;

next();
switch (token) {
Expand Down Expand Up @@ -353,6 +358,14 @@ int assemble_operand(void) {
return 0;
}

void assemble_unop(void) {
int pc = PC++;
int a;
int op = token - (tJSR - 1);
a = assemble_operand();
image[pc] = (op << 4) | (a << 10);
}

void assemble_binop(void) {
u16 pc = PC++;
int a, b;
Expand Down Expand Up @@ -389,7 +402,6 @@ void assemble_jump(void) {
}

void assemble(const char *fn) {
u16 pc, n;
fin = fopen(fn, "r");
filename = fn;
linenumber = 0;
Expand Down Expand Up @@ -424,10 +436,10 @@ void assemble(const char *fn) {
case tPUSH: case tPOP: case tNOP:
assemble_binop();
continue;
case tJSR:
pc = PC++;
n = assemble_operand();
image[pc] = (n << 10) | 0x0010;
case tJSR: case tINT: case tIAG: case tIAS:
case tRFI: case tIAQ: case tHWN: case tHWQ:
case tHWI:
assemble_unop();
continue;
default:
die("unexpected: %s", tnames[token]);
Expand All @@ -437,6 +449,8 @@ void assemble(const char *fn) {
fclose(fin);
}

#ifndef A16_EMBEDDED

void emit(const char *fn, enum outformat format) {
FILE *fp;
u16 *pc = image;
Expand Down Expand Up @@ -469,6 +483,17 @@ void emit(const char *fn, enum outformat format) {
} else if (format == OUTFORMAT_BINARY) {
/* XXX handle host endian */
fwrite(pc, sizeof(*pc), 1, fp);
} else if (format == OUTFORMAT_C) {
if (note[pc-image] == 'd') {
fprintf(fp, "0x%04x,\n", *pc);
dis = pc + 1;
} else if (pc == dis) {
char out[128];
dis = disassemble(pc, out);
fprintf(fp, "0x%04x,\t// 0x%04x:\t%s\n", *pc, (unsigned)(pc-image), out);
} else {
fprintf(fp, "0x%04x, \n", *pc);
}
}
pc++;
}
Expand Down Expand Up @@ -515,6 +540,8 @@ int main(int argc, char **argv) {
oformat = OUTFORMAT_HEX;
} else if (!strcasecmp(optarg, "pretty")) {
oformat = OUTFORMAT_PRETTY;
} else if (!strcasecmp(optarg, "c")) {
oformat = OUTFORMAT_C;
} else {
usage(argc, argv);
return 1;
Expand Down Expand Up @@ -547,4 +574,5 @@ int main(int argc, char **argv) {
}
return 0;
}
#endif

8 changes: 4 additions & 4 deletions dcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ extern u16 *disassemble(u16 *pc, char *out);

void dumpheader(void) {
fprintf(stderr,
"PC SP OV A B C X Y Z I J Instruction\n"
"---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -----------\n");
"PC SP OV IAQ 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 %s\n",
d->pc, d->sp, d->ov,
"%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %s\n",
d->pc, d->sp, d->ov, d->iaq_ind,
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);
Expand Down
11 changes: 9 additions & 2 deletions disassemble.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ static const char *opcode[] = {
"XXX", "MOV", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL",
"SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB",
};

static const char *extended_opcode[] = {
"YYY", "JSR", "RS1", "RS2", "RS3", "RS4", "RS5", "RS6",
"INT", "IAG", "IAS", "RFI", "IAQ", "RS7", "RS8", "RS9",
"HWN", "HWQ", "HWI",
};

static const char regs[8] = "ABCXYZIJ";

static u16 *dis_operand(u16 *pc, u16 n, char *out) {
Expand Down Expand Up @@ -82,8 +89,8 @@ u16 *disassemble(u16 *pc, char *out) {
pc = dis_operand(pc, b, out+strlen(out));
return pc;
}
if (a == 1) {
sprintf(out,"JSR ");
if (a > 0 && a <= 0x12) {
sprintf(out,"%s ",extended_opcode[a]);
pc = dis_operand(pc, b, out+strlen(out));
return pc;
}
Expand Down
120 changes: 115 additions & 5 deletions emulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>

#include "emulator.h"

extern u16 *disassemble(u16 *pc, char *out);

static u16 lit[0x20] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Expand Down Expand Up @@ -93,12 +93,74 @@ void dcpu_skip(struct dcpu *d) {
d->pc += skiptable[(op >> 4) & 31];
}

void dcpu_interrupt(struct dcpu *d, u16 src) {
// we assume we are not called with a dequed interrupt when qeueing is on...
if (d->iaq_en) {
if (d->iaq_ind < 256) {
d->iaq[d->iaq_ind++] = src;
}
else {
printf("iaq overflow src=0x%04x\n", src);
}
} else {
d->m[--(d->sp)] = d->r[0];
d->m[--(d->sp)] = d->pc;
d->pc = d->ia;
d->r[0] = src;
d->iaq_en = true;
}
}

int dcpu_add_module(struct dcpu *d, struct module *m) {
int index = d->module_count;

if (index >= MAX_MODULES) {
printf("Out of modules!\n");
return -1;
}

d->module_count++;
d->modules[index] = m;

return index;
}

void dcpu_start_modules(struct dcpu *d) {
for (int i = 0; i < d->module_count; i++) {
d->modules[i]->start(d, d->modules[i]);
}
}

void dcpu_stop_modules(struct dcpu *d) {
for (int i = 0; i < d->module_count; i++) {
d->modules[i]->stop(d, d->modules[i]);
}
}

void dcpu_idle_modules(struct dcpu *d) {
for (int i = 0; i < d->module_count; i++) {
d->modules[i]->idle(d, d->modules[i]);
}
}

void dcpu_step(struct dcpu *d) {
u16 op = d->m[d->pc++];
u16 op;
u16 dst;
u32 res;
u16 a, b, *aa;

if (d->stop) {
return;
}

// if iaq is off, deal with any queued interrupts (max 1 per instruction)
if (!d->iaq_en && d->iaq_ind > 0) {
dcpu_interrupt(d, d->iaq[--d->iaq_ind]);
return;
}

op = d->m[d->pc++];

if ((op & 0xF) == 0) goto extended;

aa = dcpu_opr(d, dst = (op >> 4) & 0x3F);
Expand All @@ -107,7 +169,7 @@ void dcpu_step(struct dcpu *d) {

switch (op & 0xF) {
case 0x1: res = b; break;
case 0x2: res = a + b; d->ov = res >> 16; break;
case 0x2: res = a + b; d->ov = res >> 16; break;
case 0x3: res = a - b; d->ov = res >> 16; break;
case 0x4: res = a * b; d->ov = res >> 16; break;
case 0x5: if (b) { res = a / b; } else { res = 0; } d->ov = res >> 16; break;
Expand All @@ -127,14 +189,62 @@ void dcpu_step(struct dcpu *d) {
return;

extended:
a = *dcpu_opr(d, op >> 10);
aa = dcpu_opr(d, op >> 10);
a = *aa;
switch ((op >> 4) & 0x3F) {
case 0x01:
d->m[--(d->sp)] = d->pc;
d->pc = a;
return;
case 0x08:
if (d->ia) {
dcpu_interrupt(d, a);
}
return;
case 0x09:
*aa = d->ia;
return;
case 0x0a:
d->ia = a;
return;
case 0x0b:
d->iaq_en = false;
d->pc = d->m[d->sp++];
d->r[0] = d->m[d->sp++];
return;
case 0x0c:
d->iaq_en = a != 0;
return;
case 0x10:
*aa = d->module_count;
return;
case 0x11:
if (a >= d->module_count) {
printf("invalid module index: %d\n", a);
d->r[0] = 0;
d->r[1] = 0;
d->r[2] = 0;
d->r[3] = 0;
d->r[4] = 0;
} else {
d->modules[a]->hwq(d, d->modules[a]);
}
return;
case 0x12:
if (a >= d->module_count) {
printf("invalid module index: %d\n", a);
d->r[0] = 0;
d->r[1] = 0;
d->r[2] = 0;
d->r[3] = 0;
d->r[4] = 0;
} else {
d->modules[a]->hwi(d, d->modules[a]);
}
return;
default:
fprintf(stderr, "< ILLEGAL OPCODE >\n");
exit(0);
d->stop = true;
return;
}
}
38 changes: 36 additions & 2 deletions emulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,53 @@
#ifndef _DCPU_H_
#define _DCPU_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;

#ifndef DCPU_WORDS
#define DCPU_WORDS 65536
#endif

#define MAX_MODULES 16

struct dcpu;

struct module {
void (*hwq)(struct dcpu * d, struct module * module);
void (*hwi)(struct dcpu * d, struct module * module);
void (*start)(struct dcpu * d, struct module * module);
void (*stop)(struct dcpu * d, struct module * module);
void (*idle)(struct dcpu * d, struct module * module);
};

struct dcpu {
u16 r[8];
u16 pc;
u16 sp;
u16 ov;
u16 unused;
u16 m[65536];
u16 stop;
u16 ia;
u16 iaq_en;
u16 iaq_ind;
u16 iaq[256];
u16 module_count;
u16 m[DCPU_WORDS];
struct module * modules[MAX_MODULES];
};

int dcpu_add_module(struct dcpu *d, struct module *m);
void dcpu_start_modules(struct dcpu *d);
void dcpu_stop_modules(struct dcpu *d);

void dcpu_step(struct dcpu *d);

#ifdef __cplusplus
};
#endif

#endif
Loading