From f3b513a6a37e0dd2c109d3e31bdcb35ab716c6eb Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 16 Apr 2012 19:07:07 +0000 Subject: DCPU-16 Assembler and Emulator --- Makefile | 10 +++ dcpu16.h | 47 ++++++++++ emu.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gramar.y | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lexer.l | 121 +++++++++++++++++++++++++ main.c | 93 +++++++++++++++++++ tui.c | 172 +++++++++++++++++++++++++++++++++++ 7 files changed, 1028 insertions(+) create mode 100644 Makefile create mode 100644 dcpu16.h create mode 100644 emu.c create mode 100644 gramar.y create mode 100644 lexer.l create mode 100644 main.c create mode 100644 tui.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6021e10 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +# $Id$ + +PROG= dcpu +SRCS= gramar.y lexer.l emu.c main.c tui.c +NOMAN= +LDADD+= -lcurses +#DEBUG= -Wall -ggdb -pg +#YFLAGS= -dtv + +.include diff --git a/dcpu16.h b/dcpu16.h new file mode 100644 index 0000000..646dd5c --- /dev/null +++ b/dcpu16.h @@ -0,0 +1,47 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, dATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DCPU16_H +#define _DCPU16_H + +enum { A, B, C, X, Y, Z, I, J, PC, SP, O, Aux, nReg }; + +enum { EXT, SET, ADD, SUB, MUL, DIV, MOD, SHL, + SHR, AND, BOR, XOR, IFE, IFN, IFG, IFB, nOpt }; + +enum { Res, JSR, BRK, nExt }; + +#define MEMSZ 0x10000 + +#define DISP 0x8000 +#define DISPEND 0x8180 + +#define CHARS 0x8180 +#define CHAREND 0x8280 + +#define MISC 0x8280 /* bg color */ +#define MISCEND 0x8281 + +#define KEYB 0x9000 +#define KEYP 0x9010 + +/* display: 32x12 (128x96) + 16 pixel boarder, font 8x4 */ + +unsigned short *compile(FILE *); +int step(unsigned short *, unsigned short *); + +#endif diff --git a/emu.c b/emu.c new file mode 100644 index 0000000..9a4d947 --- /dev/null +++ b/emu.c @@ -0,0 +1,305 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, dATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "dcpu16.h" + +unsigned short *mem; +unsigned short *reg; + +unsigned short skip = 0; +unsigned short run = 1; + +void ext(unsigned short *a, unsigned short *b); +void set(unsigned short *a, unsigned short *b); +void add(unsigned short *a, unsigned short *b); +void sub(unsigned short *a, unsigned short *b); +void mul(unsigned short *a, unsigned short *b); +void div(unsigned short *a, unsigned short *b); +void mod(unsigned short *a, unsigned short *b); +void shl(unsigned short *a, unsigned short *b); +void shr(unsigned short *a, unsigned short *b); +void and(unsigned short *a, unsigned short *b); +void bor(unsigned short *a, unsigned short *b); +void xor(unsigned short *a, unsigned short *b); +void ife(unsigned short *a, unsigned short *b); +void ifn(unsigned short *a, unsigned short *b); +void ifg(unsigned short *a, unsigned short *b); +void ifb(unsigned short *a, unsigned short *b); + +void (*op[nOpt])(unsigned short *a, unsigned short *b) = { + [EXT] = ext, + [SET] = set, + [ADD] = add, + [SUB] = sub, + [MUL] = mul, + [DIV] = div, + [MOD] = mod, + [SHL] = shl, + [SHR] = shr, + [AND] = and, + [BOR] = bor, + [XOR] = xor, + [IFE] = ife, + [IFN] = ifn, + [IFG] = ifg, + [IFB] = ifb, +}; + +void jsr(unsigned short *a); +void brk(unsigned short *a); + +void (*extop[nExt])(unsigned short *a) = { + [Res] = brk, /* die on wrong opcode */ + [JSR] = jsr, + [BRK] = brk, +}; + +void +ext(unsigned short *a, unsigned short *b) +{ + extop[*a](b); +} + +void +set(unsigned short *a, unsigned short *b) +{ + *a = *b; +} + +void +add(unsigned short *a, unsigned short *b) +{ + int tmp = *a; + + tmp += *b; + reg[O] = tmp > 0xFFFF; + + *a = tmp; +} + +void +sub(unsigned short *a, unsigned short *b) +{ + int tmp = *a; + + tmp -= *b; + reg[O] = tmp < 0; + + *a = tmp; +} + +void +mul(unsigned short *a, unsigned short *b) +{ + int tmp = *a; + + tmp *= *b; + reg[O] = tmp >> 16; + + *a = tmp; +} + +void +div(unsigned short *a, unsigned short *b) +{ + int tmp = *a; + + if (*b == 0) { + reg[O] = 0; + *a = 0; + } else { + reg[O] = ((tmp << 16) / *b); + *a /= *b; + } +} + +void +mod(unsigned short *a, unsigned short *b) +{ + if (*b == 0) + *a = 0; + else + *a %= *b; +} + +void +shl(unsigned short *a, unsigned short *b) +{ + int tmp = *a; + + reg[O] = ((tmp << *b) >> 16); + *a <<= *b; +} + +void +shr(unsigned short *a, unsigned short *b) +{ + int tmp = *a; + + reg[O] = ((tmp << 16) >> *b); + *a >>= *b; +} + +void +and(unsigned short *a, unsigned short *b) +{ + *a &= *b; +} + +void +bor(unsigned short *a, unsigned short *b) +{ + *a |= *b; +} + +void +xor(unsigned short *a, unsigned short *b) +{ + *a ^= *b; +} + +void +ife(unsigned short *a, unsigned short *b) +{ + skip = !(*a == *b); +} + +void +ifn(unsigned short *a, unsigned short *b) +{ + skip = !(*a != *b); +} + +void +ifg(unsigned short *a, unsigned short *b) +{ + skip = !(*a > *b); +} + +void +ifb(unsigned short *a, unsigned short *b) +{ + skip = !(*a & *b); +} + +void +jsr(unsigned short *a) +{ + mem[--reg[SP]] = reg[PC]; + reg[PC] = *a; +} + +void +brk(unsigned short *a) +{ + run = 0; +} + +unsigned short * +fetcharg(int a) +{ + switch (a) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + /* register */ + return ®[a]; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + /* [register] */ + return &mem[reg[a - 0x08]]; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + /* [next word + register] */ + return &mem[mem[reg[PC]++] + reg[a - 0x10]]; + case 0x18: + /* pop */ + return &mem[reg[SP]++]; + case 0x19: + /* peek */ + return &mem[reg[SP]]; + case 0x1a: + /* push */ + return &mem[--reg[SP]]; + case 0x1b: + /* SP */ + return ®[SP]; + case 0x1c: + /* PC */ + return ®[PC]; + case 0x1d: + /* O */ + return ®[O]; + case 0x1e: + /* [next word] */ + return &mem[mem[reg[PC]++]]; + case 0x1f: + /* next word */ + return &mem[reg[PC]++]; + default: + /* literal */ + reg[Aux] = a - 0x20; + return ®[Aux]; + } +} + +int +step(unsigned short *m, unsigned short *r) +{ + unsigned short c, o, *a, *b, s; + + if (!run) + return -1; + + mem = m; + reg = r; + + c = mem[reg[PC]++]; + s = reg[SP]; /* store SP */ + + o = c & 0x0f; + reg[Aux] = (c >> 4) & 0x3f; + /* don't fetch first arg for extended opcodes */ + a = o ? fetcharg(reg[Aux]) : ®[Aux]; + b = fetcharg((c >> 10) & 0x3f); + + if (skip) { + skip = 0; + reg[SP] = s; /* restore SP on skipped opcode */ + } else + op[o](a, b); + + return 0; +} diff --git a/gramar.y b/gramar.y new file mode 100644 index 0000000..61fdd1a --- /dev/null +++ b/gramar.y @@ -0,0 +1,280 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, dATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +%{ +#include +#include +#include +#include "dcpu16.h" + +extern int yylineno; +extern FILE *yyin; +int yylex(void); +int yyparse(void); + +#if YYDEBUG +extern int yydebug; +#endif + +struct { + unsigned short val; + char *label; +} stack[0x100], ref[0x100]; + +int sp = 0; +int rp = 0; +int pc = 0; + +unsigned short buffer[MEMSZ]; +char *label[MEMSZ]; + +%} + +%union { + int ival; + char *sval; +}; + +%token A B C X Y Z I J +%token POP PEEK PUSH SP PC O +%token SET ADD SUB MUL DIV MOD SHL SHR AND BOR XOR IFE IFN IFG IFB +%token DAT JSR BRK ORG JMP +%token LBR RBR LBRACE RBRACE LPAR RPAR +%token COMMA DP PLUS MINUS MULT +%token DOT HASH MACRO INCLUDE +%token NUMBER +%token STRING QSTRING + +%type register opcode extended value expr + +%left PLUS MINUS +%left MULT + +%% + +prog + : /* empty */ + | prog statement + ; + +statement + : opcode value COMMA value + { + popop(($4 << 10) | ($2 << 4) | $1); + popall(); + } + | opcode value + { + popop(($2 << 10) | $1); + popall(); + } + | opcode { popop($1); } + | DP STRING { addref($2); } + | DAT data { popall(); } + | ORG expr { pc = $2; } + ; + +data + : /* empty */ + | data block + | data COMMA block + ; + +expr + : NUMBER { $$ = $1; } + | expr PLUS expr { $$ = $1 + $3; } + | expr MINUS expr { $$ = $1 - $3; } + | expr MULT expr { $$ = $1 * $3; } + | LPAR expr RPAR { $$ = $2; } + ; + +block + : QSTRING + { + char *s = $1; + while (*s) + push(*s++, NULL); + } + | STRING { push(0, $1); } + | expr { push($1, NULL); } + ; + +value + : register { $$ = $1; } + | LBR register RBR { $$ = 0x08 + $2; } + | POP { $$ = 0x18; } + | PEEK { $$ = 0x19; } + | PUSH { $$ = 0x1a; } + | SP { $$ = 0x1b; } + | PC { $$ = 0x1c; } + | O { $$ = 0x1d; } + | LBR expr RBR + { + $$ = 0x1e; + push($2, NULL); + } + | LBR STRING RBR + { + $$ = 0x1e; + push(0, $2); + } + | LBR expr PLUS register RBR + { + $$ = 0x10 + $4; + push($2, NULL); + } + | LBR register PLUS expr RBR + { + $$ = 0x10 + $2; + push($4, NULL); + } + | LBR STRING PLUS register RBR + { + $$ = 0x10 + $4; + push(0, $2); + } + | LBR register PLUS STRING RBR + { + $$ = 0x10 + $2; + push(0, $4); + } + | expr + { + if ($1 < 0x20) + $$ = 0x20 + $1; + else { + $$ = 0x1f; + push($1, NULL); + } + } + | STRING + { + $$ = 0x1f; + push(0, $1); + } + ; + +register + : A { $$ = 0x00; } + | B { $$ = 0x01; } + | C { $$ = 0x02; } + | X { $$ = 0x03; } + | Y { $$ = 0x04; } + | Z { $$ = 0x05; } + | I { $$ = 0x06; } + | J { $$ = 0x07; } + ; + +opcode + : extended { $$ = $1 << 4; } + | SET { $$ = 0x01; } + | ADD { $$ = 0x02; } + | SUB { $$ = 0x03; } + | MUL { $$ = 0x04; } + | DIV { $$ = 0x05; } + | MOD { $$ = 0x06; } + | SHL { $$ = 0x07; } + | SHR { $$ = 0x08; } + | AND { $$ = 0x09; } + | BOR { $$ = 0x0a; } + | XOR { $$ = 0x0b; } + | IFE { $$ = 0x0c; } + | IFN { $$ = 0x0d; } + | IFG { $$ = 0x0e; } + | IFB { $$ = 0x0f; } + ; + +extended + : JSR { $$ = 0x01; } + | BRK { $$ = 0x02; } + ; + + +%% + +void +yyerror(const char *s) +{ + fprintf(stderr, "Line %d: %s\n", yylineno, s); + exit(1); +} + +void +push(int i, char *s) +{ + stack[sp].val = i; + stack[sp++].label = s; +} + +void +popop(int n) +{ + buffer[pc++] = n; +} + +void +popall(void) +{ + int n = sp; + + while (sp > 0) { + buffer[pc] = stack[n - sp].val; + label[pc++] = stack[n - sp--].label; + } +} + +void +addref(char *s) +{ + ref[rp].label = s; + ref[rp++].val = pc; +} + +int +findref(char *s) +{ + int i; + + for (i = 0; i < rp; i++) + if (strcmp(ref[i].label, s) == 0) + return ref[i].val; + + return 0; +} + +void +restorerefs(void) +{ + int i; + + for (i = 0; i < pc; i++) + if (label[i]) + buffer[i] = findref(label[i]); +} + +unsigned short * +compile(FILE *fd) +{ +#if YYDEBUG + yydebug = 1; +#endif + yyin = fd; + yyparse(); + restorerefs(); + + return buffer; +} diff --git a/lexer.l b/lexer.l new file mode 100644 index 0000000..f157edf --- /dev/null +++ b/lexer.l @@ -0,0 +1,121 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +%{ +#include +#include +#include +#include "y.tab.h" +%} + +%option yylineno + +%x COMMENT QUOTED + +WS [ \t\r\n]+ +STR [A-Za-z0-9_]+ +HEX 0x[0-9A-Fa-f]+ +OCT 0[0-7]+ +DEC [0-9]+ + +%% + +[Ss][Ee][Tt] return SET; +[Aa][Dd][Dd] return ADD; +[Ss][Uu][Bb] return SUB; +[Mm][Uu][Ll] return MUL; +[Dd][Ii][Vv] return DIV; +[Mm][Oo][Dd] return MOD; +[Ss][Hh][Ll] return SHL; +[Ss][Hh][Rr] return SHR; +[Aa][Nn][Dd] return AND; +[Bb][Oo][Rr] return BOR; +[Xx][Oo][Rr] return XOR; +[Ii][Ff][Ee] return IFE; +[Ii][Ff][Nn] return IFN; +[Ii][Ff][Gg] return IFG; +[Ii][Ff][Bb] return IFB; + +[Jj][Ss][Rr] return JSR; +[Bb][Rr][Kk] return BRK; +[Dd][Aa][Tt] return DAT; +[Oo][Rr][Gg] return ORG; +[Jj][Mm][Pp] return JMP; + +[Pp][Oo][Pp] return POP; +[Pp][Ee][Ee][Kk] return PEEK; +[Pp][Uu][Ss][Hh] return PUSH; +[Ss][Pp] return SP; +[Pp][Cc] return PC; +[Oo] return O; + +[Aa] return A; +[Bb] return B; +[Cc] return C; +[Xx] return X; +[Yy] return Y; +[Zz] return Z; +[Ii] return I; +[Jj] return J; + +"+" return PLUS; +"-" return MINUS; +"*" return MULT; +"," return COMMA; +":" return DP; +"[" return LBR; +"]" return RBR; +"(" return LPAR; +")" return RPAR; +"{" return LBRACE; +"}" return RBRACE; +"#" return HASH; +"." return DOT; + +[Mm][Aa][Cc][Rr][Oo] return MACRO; +[Ii][Nn][Cc][Ll][Uu][Dd][Ee] return INCLUDE; + +";" BEGIN(COMMENT); +[\r\n]+ BEGIN(INITIAL); +. /* eat comments */ + +"\"" BEGIN(QUOTED); +[^\"]+ { + yylval.sval = strdup(yytext); + return QSTRING; + } +"\"" BEGIN(INITIAL); + +{HEX}|{OCT}|{DEC} { + yylval.ival = strtol(yytext, (char **)NULL, 0); + return NUMBER; + } + +{STR} { + yylval.sval = strdup(yytext); + return STRING; + } + +{WS} /* eat whitespace */ + +%% + +int +yywrap(void) +{ + return 1; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..35a7411 --- /dev/null +++ b/main.c @@ -0,0 +1,93 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, dATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "dcpu16.h" + +void +dumpcode(unsigned short *m) +{ + int i, k, sum; + + for (i = 0; i < MEMSZ; i += 8) { + sum = 0; + for (k = 0; k < 8; k++) + sum += m[i + k]; + if (!sum) + continue; + printf("%4.4x:", i); + for (k = 0; k < 8; k++) + printf("%5.4x", m[i + k]); + printf("\n"); + } +} + +void +usage(void) +{ + extern char *__progname; + + (void)fprintf(stderr, "Usage: %s [-gt]\n", __progname); + exit(1); +} + +int +main(int argc, char **argv) +{ + unsigned short *m; + unsigned short r[nReg] = { 0 }; + FILE *fd; + int e_flag = 0; + int g_flag = 0; + int ch; + + while ((ch = getopt(argc, argv, "gt")) != -1) + switch (ch) { + case 'g': + g_flag = 1; + break; + case 't': + e_flag = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + + argc -= optind; + argv += optind; + + if (!argc) + usage(); + + fd = fopen(*argv, "r"); + if (!fd) + err(1, "cannot open file"); + + m = compile(fd); + fclose(fd); + + if (e_flag) + tuiemu(m, r); + else + dumpcode(m); + + return 0; +} diff --git a/tui.c b/tui.c new file mode 100644 index 0000000..3a61c90 --- /dev/null +++ b/tui.c @@ -0,0 +1,172 @@ +/* $Id$ */ +/* + * Copyright (c) 2012 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, dATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include "dcpu16.h" + +WINDOW *outbox, *out, *regbox, *regs, *code; + +void +dumpmem(unsigned short *m) +{ + int i, k, sum, lines = 0; + + wmove(code, 0, 0); + + for (i = 0; i < MEMSZ; i += 8) { + if (++lines > 24) + break; + for (sum = 0, k = 0; k < 8; k++) + sum += m[i + k]; + if (!sum) + continue; + wprintw(code, "%4.4x:", i); + for (k = 0; k < 8; k++) + wprintw(code, "%5.4x", m[i + k]); + wprintw(code, "\n"); + } + + wnoutrefresh(code); +} + +void +dumpdisp(unsigned short *m) +{ + int i; + char c, b, hbg, bg, hfg, fg, col; + + wmove(out, 0, 0); + + for (i = DISP; i < DISPEND; i++) { + c = m[i] & 0x7f; + + b = (m[i] >> 7) & 0x01; + bg = (m[i] >> 8) & 0x07; + hbg = (m[i] >> 11) & 0x01; + fg = (m[i] >> 12) & 0x07; + hfg = (m[i] >> 15) & 0x01; + + col = (fg << 3) | bg; + + if (!(isascii(c) && isprint(c))) + c = ' '; + + if (b) + wattron(out, A_BLINK); + if (hfg) + wattron(out, A_BOLD); + wattron(out, COLOR_PAIR(col)); + waddch(out, c); + wattroff(out, COLOR_PAIR(col)); + if (hfg) + wattroff(out, A_BOLD); + if (b) + wattroff(out, A_BLINK); + } + + wnoutrefresh(out); +} + +void +dumpreg(unsigned short *mem, unsigned short *reg) +{ + wmove(regs, 0, 0); + + mvwprintw(regs, 0, 0, " A: %4.4x [%4.4x]", reg[A], mem[reg[A]]); + mvwprintw(regs, 1, 0, " B: %4.4x [%4.4x]", reg[B], mem[reg[B]]); + mvwprintw(regs, 2, 0, " C: %4.4x [%4.4x]", reg[C], mem[reg[C]]); + + mvwprintw(regs, 3, 0, " X: %4.4x [%4.4x]", reg[X], mem[reg[X]]); + mvwprintw(regs, 4, 0, " Y: %4.4x [%4.4x]", reg[Y], mem[reg[Y]]); + mvwprintw(regs, 5, 0, " Z: %4.4x [%4.4x]", reg[Z], mem[reg[Z]]); + + mvwprintw(regs, 6, 0, " I: %4.4x [%4.4x]", reg[I], mem[reg[I]]); + mvwprintw(regs, 7, 0, " J: %4.4x [%4.4x]", reg[J], mem[reg[J]]); + + mvwprintw(regs, 0, 16, "PC: %4.4x [%4.4x]", reg[PC], mem[reg[PC]]); + mvwprintw(regs, 1, 16, "SP: %4.4x [%4.4x]", reg[SP], mem[reg[SP]]); + mvwprintw(regs, 2, 16, " O: %4.4x [%4.4x]", reg[O], mem[reg[O]]); + + wnoutrefresh(regs); +} + +void +init_colors() +{ + int i, j; + int I, J; + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) { + /* Notch is jerk, why RGB istead of BGR??? */ + I = (i >> 2) | (i & 0x02) | ((i << 2) & 0x04); + J = (j >> 2) | (j & 0x02) | ((j << 2) & 0x04); + init_pair((i << 3) | j, I, J); + } +} + +void +tuiemu(unsigned short *m, unsigned short *r) +{ + int ch; + + initscr(); + + noecho(); + nodelay(stdscr, TRUE); + + start_color(); + init_colors(); + + outbox = derwin(stdscr, 14, 34, 0, 46); + out = derwin(outbox, 12, 32, 1, 1); + box(outbox, 0, 0); + wnoutrefresh(outbox); + + regbox = derwin(stdscr, 10, 34, 14, 46); + regs = derwin(regbox, 8, 32, 1, 1); + box(regbox, 0, 0); + wnoutrefresh(regbox); + + code = derwin(stdscr, 24, 46, 0, 0); + + m[KEYP] = KEYB; + + while (step(m, r) != -1) { + dumpmem(m); + dumpdisp(m); + dumpreg(m, r); + if ((ch = wgetch(stdscr)) != ERR) { + m[m[KEYP]] = ch; + m[KEYP] = KEYB + (m[KEYP] + 1) % 0x10; + } + doupdate(); + } + + delwin(code); + delwin(regs); + delwin(regbox); + delwin(out); + delwin(outbox); + + endwin(); +} -- cgit v1.2.3