diff options
author | spew <devnull@localhost> | 2017-01-10 11:42:11 -0600 |
---|---|---|
committer | spew <devnull@localhost> | 2017-01-10 11:42:11 -0600 |
commit | a0cc369c15bdd404e1a60b4fd5b3a5156a041f74 (patch) | |
tree | 5e0105c719efc7fbdbcf3a4cbe9b9acca6a2255b /sys/src/games | |
parent | c67d0c699f7b52da534f75d3620776997b1e8d52 (diff) |
games/mix: Add Knuth MIX emulator/assembler
Diffstat (limited to 'sys/src/games')
-rw-r--r-- | sys/src/games/mix/char.c | 124 | ||||
-rw-r--r-- | sys/src/games/mix/mix.c | 1129 | ||||
-rw-r--r-- | sys/src/games/mix/mix.h | 85 | ||||
-rw-r--r-- | sys/src/games/mix/mixal.y | 359 | ||||
-rw-r--r-- | sys/src/games/mix/mkfile | 13 | ||||
-rw-r--r-- | sys/src/games/mix/repl.c | 289 | ||||
-rw-r--r-- | sys/src/games/mix/tests/maximum.m | 14 | ||||
-rw-r--r-- | sys/src/games/mix/tests/maxmain.m | 25 | ||||
-rw-r--r-- | sys/src/games/mix/tests/primes.m | 49 | ||||
-rw-r--r-- | sys/src/games/mix/util.c | 147 | ||||
-rw-r--r-- | sys/src/games/mkfile | 1 |
11 files changed, 2235 insertions, 0 deletions
diff --git a/sys/src/games/mix/char.c b/sys/src/games/mix/char.c new file mode 100644 index 000000000..3b5d57cbe --- /dev/null +++ b/sys/src/games/mix/char.c @@ -0,0 +1,124 @@ +#include <u.h> +#include <libc.h> +#include <avl.h> +#include <bio.h> +#include "mix.h" + +typedef +struct Mixchar { + Rune r; + int m; +} Mixchar; + +static Rune mixtor[] = { + ' ', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + L'Δ', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + L'Σ', + L'Π', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '.', + ',', + '(', + ')', + '+', + '-', + '*', + '/', + '=', + '$', + '<', + '>', + '@', + ';', + ':', + '\'' +}; + +static Mixchar rtomix[nelem(mixtor)]; + +static int +runecmp(void *a, void *b) +{ + Rune ra, rb; + + ra = ((Mixchar*)a)->r; + rb = ((Mixchar*)b)->r; + + if(ra < rb) + return -1; + if(ra > rb) + return 1; + return 0; +} + +void +cinit(void) +{ + int i; + Mixchar *a; + + for(i = 0; i < nelem(rtomix); i++) { + a = rtomix+i; + a->r = mixtor[i]; + a->m = i; + } + qsort(rtomix, nelem(rtomix), sizeof(*rtomix), runecmp); +} + +int +runetomix(Rune r) +{ + Mixchar *c, l; + + l.r = r; + c = (Mixchar*)bsearch(&l, rtomix, nelem(rtomix), sizeof(*rtomix), runecmp); + if(c == nil) { + print("Not found!!\n"); + return -1; + } + + return c->m; +} + +Rune +mixtorune(int m) +{ + if(m < nelem(mixtor)) + return mixtor[m]; + return -1; +} diff --git a/sys/src/games/mix/mix.c b/sys/src/games/mix/mix.c new file mode 100644 index 000000000..64bad770c --- /dev/null +++ b/sys/src/games/mix/mix.c @@ -0,0 +1,1129 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <bio.h> +#include <avl.h> +#include "mix.h" +#include "y.tab.h" + +struct Resvd { + char *name; + long lex; + int c; + int f; +} res[] = { + { "NOP", LOP, 0, F(0, 5) }, + { "ADD", LOP, 1, F(0, 5) }, + { "FADD", LOP, 1, 6 }, + { "SUB", LOP, 2, F(0, 5) }, + { "FSUB", LOP, 2, 6 }, + { "MUL", LOP, 3, F(0, 5) }, + { "FMUL", LOP, 3, 6 }, + { "DIV", LOP, 4, F(0, 5) }, + { "FDIV", LOP, 4, 6 }, + { "NUM", LOP, 5, 0 }, + { "CHAR", LOP, 5, 1 }, + { "HLT", LOP, 5, 2 }, + { "SLA", LOP, 6, 0 }, + { "SRA", LOP, 6, 1 }, + { "SLAX", LOP, 6, 2 }, + { "SRAX", LOP, 6, 3 }, + { "SLC", LOP, 6, 4 }, + { "SRC", LOP, 6, 5 }, + { "MOVE", LOP, 7, 1 }, + { "LDA", LOP, 8, F(0, 5) }, + { "LD1", LOP, 9, F(0, 5) }, + { "LD2", LOP, 10, F(0, 5) }, + { "LD3", LOP, 11, F(0, 5) }, + { "LD4", LOP, 12, F(0, 5) }, + { "LD5", LOP, 13, F(0, 5) }, + { "LD6", LOP, 14, F(0, 5) }, + { "LDX", LOP, 15, F(0, 5) }, + { "LDAN", LOP, 16, F(0, 5) }, + { "LD1N", LOP, 17, F(0, 5) }, + { "LD2N", LOP, 18, F(0, 5) }, + { "LD3N", LOP, 19, F(0, 5) }, + { "LD4N", LOP, 20, F(0, 5) }, + { "LD5N", LOP, 21, F(0, 5) }, + { "LD6N", LOP, 22, F(0, 5) }, + { "LDXN", LOP, 23, F(0, 5) }, + { "STA", LOP, 24, F(0, 5) }, + { "ST1", LOP, 25, F(0, 5) }, + { "ST2", LOP, 26, F(0, 5) }, + { "ST3", LOP, 27, F(0, 5) }, + { "ST4", LOP, 28, F(0, 5) }, + { "ST5", LOP, 29, F(0, 5) }, + { "ST6", LOP, 30, F(0, 5) }, + { "STX", LOP, 31, F(0, 5) }, + { "STJ", LOP, 32, F(0, 2) }, + { "STZ", LOP, 33, F(0, 5) }, + { "JBUS", LOP, 34, 0 }, + { "IOC", LOP, 35, 0 }, + { "IN", LOP, 36, 0 }, + { "OUT", LOP, 37, 0 }, + { "JRED", LOP, 38, 0 }, + { "JMP", LOP, 39, 0 }, + { "JSJ", LOP, 39, 1 }, + { "JOV", LOP, 39, 2 }, + { "JNOV", LOP, 39, 3 }, + { "JL", LOP, 39, 4 }, + { "JE", LOP, 39, 5 }, + { "JG", LOP, 39, 6 }, + { "JGE", LOP, 39, 7 }, + { "JNE", LOP, 39, 8 }, + { "JLE", LOP, 39, 9 }, + { "JAN", LOP, 40, 0 }, + { "JAZ", LOP, 40, 1 }, + { "JAP", LOP, 40, 2 }, + { "JANN", LOP, 40, 3 }, + { "JANZ", LOP, 40, 4 }, + { "JANP", LOP, 40, 5 }, + { "J1N", LOP, 41, 0 }, + { "J1Z", LOP, 41, 1 }, + { "J1P", LOP, 41, 2 }, + { "J1NN", LOP, 41, 3 }, + { "J1NZ", LOP, 41, 4 }, + { "J1NP", LOP, 41, 5 }, + { "J2N", LOP, 42, 0 }, + { "J2Z", LOP, 42, 1 }, + { "J2P", LOP, 42, 2 }, + { "J2NN", LOP, 42, 3 }, + { "J2NZ", LOP, 42, 4 }, + { "J2NP", LOP, 42, 5 }, + { "J3N", LOP, 43, 0 }, + { "J3Z", LOP, 43, 1 }, + { "J3P", LOP, 43, 2 }, + { "J3NN", LOP, 43, 3 }, + { "J3NZ", LOP, 43, 4 }, + { "J3NP", LOP, 43, 5 }, + { "J4N", LOP, 44, 0 }, + { "J4Z", LOP, 44, 1 }, + { "J4P", LOP, 44, 2 }, + { "J4NN", LOP, 44, 3 }, + { "J4NZ", LOP, 44, 4 }, + { "J4NP", LOP, 44, 5 }, + { "J5N", LOP, 45, 0 }, + { "J5Z", LOP, 45, 1 }, + { "J5P", LOP, 45, 2 }, + { "J5NN", LOP, 45, 3 }, + { "J5NZ", LOP, 45, 4 }, + { "J5NP", LOP, 45, 5 }, + { "J6N", LOP, 46, 0 }, + { "J6Z", LOP, 46, 1 }, + { "J6P", LOP, 46, 2 }, + { "J6NN", LOP, 46, 3 }, + { "J6NZ", LOP, 46, 4 }, + { "J6NP", LOP, 46, 5 }, + { "JXN", LOP, 47, 0 }, + { "JXZ", LOP, 47, 1 }, + { "JXP", LOP, 47, 2 }, + { "JXNN", LOP, 47, 3 }, + { "JXNZ", LOP, 47, 4 }, + { "JXNP", LOP, 47, 5 }, + { "INCA", LOP, 48, 0 }, + { "DECA", LOP, 48, 1 }, + { "ENTA", LOP, 48, 2 }, + { "ENNA", LOP, 48, 3 }, + { "INC1", LOP, 49, 0 }, + { "DEC1", LOP, 49, 1 }, + { "ENT1", LOP, 49, 2 }, + { "ENN1", LOP, 49, 3 }, + { "INC2", LOP, 50, 0 }, + { "DEC2", LOP, 50, 1 }, + { "ENT2", LOP, 50, 2 }, + { "ENN2", LOP, 50, 3 }, + { "INC3", LOP, 51, 0 }, + { "DEC3", LOP, 51, 1 }, + { "ENT3", LOP, 51, 2 }, + { "ENN3", LOP, 51, 3 }, + { "INC4", LOP, 52, 0 }, + { "DEC4", LOP, 52, 1 }, + { "ENT4", LOP, 52, 2 }, + { "ENN4", LOP, 52, 3 }, + { "INC5", LOP, 53, 0 }, + { "DEC5", LOP, 53, 1 }, + { "ENT5", LOP, 53, 2 }, + { "ENN5", LOP, 53, 3 }, + { "INC6", LOP, 54, 0 }, + { "DEC6", LOP, 54, 1 }, + { "ENT6", LOP, 54, 2 }, + { "ENN6", LOP, 54, 3 }, + { "INCX", LOP, 55, 0 }, + { "DECX", LOP, 55, 1 }, + { "ENTX", LOP, 55, 2 }, + { "ENNX", LOP, 55, 3 }, + { "CMPA", LOP, 56, F(0, 5) }, + { "FCMP", LOP, 56, 6 }, + { "CMP1", LOP, 57, F(0, 5) }, + { "CMP2", LOP, 58, F(0, 5) }, + { "CMP3", LOP, 59, F(0, 5) }, + { "CMP4", LOP, 60, F(0, 5) }, + { "CMP5", LOP, 61, F(0, 5) }, + { "CMP6", LOP, 62, F(0, 5) }, + { "CMPX", LOP, 63, F(0, 5) }, + { "EQU", LEQU, -1, -1 }, + { "ORIG", LORIG, -1, -1 }, + { "CON", LCON, -1, -1 }, + { "ALF", LALF, -1, -1 }, + { "END", LEND, -1, -1 }, + { "0H", LHERE, 0, -1 }, + { "1H", LHERE, 1, -1 }, + { "2H", LHERE, 2, -1 }, + { "3H", LHERE, 3, -1 }, + { "4H", LHERE, 4, -1 }, + { "5H", LHERE, 5, -1 }, + { "6H", LHERE, 6, -1 }, + { "7H", LHERE, 7, -1 }, + { "8H", LHERE, 8, -1 }, + { "9H", LHERE, 9, -1 }, + { "0B", LBACK, 0, -1 }, + { "1B", LBACK, 1, -1 }, + { "2B", LBACK, 2, -1 }, + { "3B", LBACK, 3, -1 }, + { "4B", LBACK, 4, -1 }, + { "5B", LBACK, 5, -1 }, + { "6B", LBACK, 6, -1 }, + { "7B", LBACK, 7, -1 }, + { "8B", LBACK, 8, -1 }, + { "9B", LBACK, 9, -1 }, + { "0F", LFORW, 0, -1 }, + { "1F", LFORW, 1, -1 }, + { "2F", LFORW, 2, -1 }, + { "3F", LFORW, 3, -1 }, + { "4F", LFORW, 4, -1 }, + { "5F", LFORW, 5, -1 }, + { "6F", LFORW, 6, -1 }, + { "7F", LFORW, 7, -1 }, + { "8F", LFORW, 8, -1 }, + { "9F", LFORW, 9, -1 }, +}; + +int mask[] = { + MASK1, + MASK2, + MASK3, + MASK4, + MASK5 +}; + +int symcmp(Avl*, Avl*); +Sym *sym(char*); + +void +main(int argc, char **argv) +{ + int go; + char **ap; + + go = 0; + ARGBEGIN { + case 'g': go++; break; + } ARGEND + + cinit(); + sinit(); + fmtinstall('I', Ifmt); + vmstart = -1; + for(ap = argv; ap < argv+argc; ap++) + asmfile(*ap); + repl(go); + exits(nil); +} + +void +sinit(void) +{ + struct Resvd *r; + Sym *s; + + syms = avlcreate(symcmp); + for(r = res; r < res + nelem(res); r++) { + s = sym(r->name); + s->lex = r->lex; + s->opc = r->c; + s->f = r->f; + avlinsert(syms, s); + } +} + +int +asmfile(char *file) +{ + int fd; + + if((fd = open(file, OREAD)) == -1) + return -1; + Binit(&bin, fd, OREAD); + line = 1; + filename = file; + if(setjmp(errjmp) == 0) + yyparse(); + Bterm(&bin); + close(fd); + return 0; +} + +int +unpack(u32int inst, int *apart, int *ipart, int *fpart) +{ + int opc; + + opc = V(inst, F(5, 5)); + *fpart = V(inst, F(4, 4)); + *ipart = V(inst, F(3, 3)); + *apart = V(inst, F(0, 2)); + return opc; +} + +int +Ifmt(Fmt *f) +{ + u32int inst; + int i, apart, ipart, fpart, opc, a, b; + + inst = va_arg(f->args, u32int); + opc = unpack(inst, &apart, &ipart, &fpart); + for(i = 0; i < nelem(res); i++) { + if(res[i].c == opc) + break; + } + UNF(a, b, fpart); + if(res[i+1].c != opc) + return fmtprint(f, "%s\t%d,%d(%d | %d:%d)", res[i].name, apart, ipart, fpart, a, b); + while(res[i].c == opc && i < nelem(res)) { + if(res[i].f == fpart) + return fmtprint(f, "%s\t%d,%d(%d | %d:%d)", res[i].name, apart, ipart, fpart, a, b); + i++; + } + return fmtprint(f, "%d\t%d,%d(%d | %d:%d)", opc, apart, ipart, fpart, a, b); +} + +long +yylex(void) +{ + static Rune buf[11]; + Rune r, *bp, *ep; + static char cbuf[100]; + int isnum; + + if(yydone) + return -1; + +Loop: + r = Bgetrune(&bin); + switch(r) { + case Beof: + return -1; + case '\t': + case ' ': + goto Loop; + case '\n': + line++; + case '+': + case '-': + case '*': + case ':': + case ',': + case '(': + case ')': + case '=': + return r; + case '/': + r = Bgetrune(&bin); + if(r == '/') + return LSS; + else + Bungetrune(&bin); + return '/'; + case '"': + for(bp = buf; bp < buf+5; bp++) { + *bp = Bgetrune(&bin); + } + if(Bgetrune(&bin) != '"') + yyerror("Bad string literal\n"); + yylval.rbuf = buf; + return LSTR; + case '#': + skipto('\n'); + line++; + return '\n'; + } + bp = buf; + ep = buf+nelem(buf)-1; + isnum = 1; + for(;;) { + if(runetomix(r) == -1) + yyerror("Invalid character %C", r); + if(bp == ep) + yyerror("Symbol or number too long"); + *bp++ = r; + if(isnum && (r >= Runeself || !isdigit(r))) + isnum = 0; + r = Bgetrune(&bin); + switch(r) { + case Beof: + case '\t': + case '\n': + case '+': + case '-': + case '*': + case ':': + case ',': + case '(': + case ')': + case '=': + case ' ': + case '/': + case '#': + Bungetrune(&bin); + *bp = '\0'; + goto End; + } + } +End: + seprint(cbuf, cbuf+100, "%S", buf); + if(isnum) { + yylval.lval = strtol(cbuf, nil, 10); + return LNUM; + } + yylval.sym = sym(cbuf); + return yylval.sym->lex; +} + +Sym* +sym(char *name) +{ + Sym *s, l; + + l.name = name; + s = (Sym*)avllookup(syms, &l); + if(s != nil) + return s; + + s = emallocz(sizeof(*s) + strlen(name)); + strcpy(s->nbuf, name); + s->name = s->nbuf; + s->lex = LSYMREF; + avlinsert(syms, s); + return s; +} + +int +symcmp(Avl *a, Avl *b) +{ + Sym *sa, *sb; + + sa = (Sym*)a; + sb = (Sym*)b; + return strcmp(sa->name, sb->name); +} + +void +skipto(char c) +{ + Rune r; + + for(;;) { + r = Bgetrune(&bin); + if(r != c && r != Beof) + continue; + return; + } +} + +int +mval(u32int a, int s, u32int m) +{ + int sign, val; + + sign = a >> 31; + val = a>>s*BITS & m; + if(sign) + return -val; + return val; +} + +int +V(u32int w, int f) +{ + int a, b, d; + + if(f == 0) + return 0; + + UNF(a, b, f); + if(a > 0) + w &= ~SIGNB; + else + a++; + + d = b - a; + if(a > 5 || b > 5 || d < 0 || d > 4) + vmerror("Invalid fpart %d", f); + + return mval(w, 5-b, mask[d]); +} + +int +M(int a, int i) +{ + int off, r; + + r = ri[i] & ~(MASK3<<2*BITS); + off = i == 0 ? 0 : mval(r, 0, MASK2); + return a + off; +} + +void mixfadd(int){} + +void +mixadd(int m, int f) +{ + int rval; + + rval = mval(ra, 0, MASK5); + rval += V(cells[m], f); + ra = rval < 0 ? -rval|SIGNB : rval; + if(ra & OVERB) { + ra &= ~OVERB; + ot = 1; + } +} + +void mixfsub(int){} + +void +mixsub(int m, int f) +{ + int rval; + + rval = mval(ra, 0, MASK5); + rval -= V(cells[m], f); + ra = rval < 0 ? -rval|SIGNB : rval; + if(ra & OVERB) { + ra &= ~OVERB; + ot = 1; + } +} + +void mixfmul(int){} + +void +mixmul(int m, int f) +{ + vlong rval; + int signb; + + rval = mval(ra, 0, MASK5); + rval *= V(cells[m], f); + + if(rval < 0) { + rval = -rval; + signb = SIGNB; + } else + signb = 0; + + ra = rval>>5*BITS & MASK5 | signb; + rx = rval & MASK5 | signb; +} + +void mixfdiv(int){} + +void +mixdiv(int m, int f) +{ + vlong rax, quot; + u32int xsignb, asignb; + int rem, v; + + v = V(cells[m], f); + if(v == 0) { + ot = 1; + return; + } + rax = ra & MASK5; + rax <<= 5 * BITS; + rax |= rx & MASK5; + if(ra >> 31) + rax = -rax; + + quot = rax / v; + rem = rax % v; + + if(quot < 0) { + quot = -quot; + asignb = SIGNB; + } else + asignb = 0; + + if(rem < 0) { + rem = -rem; + xsignb = SIGNB; + } else + xsignb = 0; + + if(quot & ~MASK5) + ot = 1; + + ra = quot & MASK5 | asignb; + rx = rem & MASK5 | xsignb; +} + +void +mixnum(void) +{ + int i, b; + u32int n; + + n = 0; + for(i = 0; i < 5; i++) { + b = ra>>(4-i)*BITS & MASK1; + b %= 10; + n = 10*n + b; + } + for(i = 0; i < 5; i++) { + b = rx>>(4-i)*BITS & MASK1; + b %= 10; + n = 10*n + b; + } + ra &= ~MASK5; + ra |= n & MASK5; +} + +void +mixchar(void) +{ + int i; + u32int a, val; + + val = ra & ~SIGNB; + for(i = 0; i < 5; i++) { + a = val % 10; + a += 30; + rx &= ~(MASK1 << i*BITS); + rx |= a << i*BITS; + val /= 10; + } + for(i = 0; i < 5; i++) { + a = val % 10; + a += 30; + ra &= ~(MASK1 << i*BITS); + ra |= a << i*BITS; + val /= 10; + } +} + +void +mixslra(int m, int left) +{ + u32int val; + + if(m < 0) + vmerror("Bad shift A %d", m); + if(m > 4) { + ra &= ~MASK5; + return; + } + val = ra & MASK5; + ra &= ~MASK5; + if(left) + val <<= m * BITS; + else + val >>= m * BITS; + ra |= val & MASK5; +} + +void +mixslrax(int m, int left) +{ + u64int rax; + + if(m < 0) + vmerror("Bad shift AX %d", m); + if(m > 9) { + ra &= ~MASK5; + rx &= ~MASK5; + return; + } + rax = ra & MASK5; + ra &= ~MASK5; + rax <<= 5 * BITS; + rax |= rx & MASK5; + rx &= ~MASK5; + if(left) + rax <<= m; + else + rax >>= m; + rx |= rax & MASK5; + ra |= rax>>5*BITS & MASK5; +} + +void +mixslc(int m) +{ + u64int rax, s; + + if(m < 0) + vmerror("Bad shift SLC %d", m); + + m %= 10; + + rax = ra & MASK5; + ra &= ~MASK5; + rax <<= 5 * BITS; + rax |= rx & MASK5; + rx &= ~MASK5; + + s = rax & mask[m]<<10-m; + rax <<= m; + rax &= ~mask[m]; + rax |= s; + + rx |= rax & MASK5; + ra |= rax>>5*BITS & MASK5; +} + +void +mixsrc(int m) +{ + u64int rax, s; + + if(m < 0) + vmerror("Bad shift SRC %d", m); + + m %= 10; + + rax = ra & MASK5; + ra &= ~MASK5; + rax <<= 5 * BITS; + rax |= rx & MASK5; + rx &= ~MASK5; + + s = rax & mask[m]; + rax >>= m; + rax &= ~mask[m] << 10-m; + rax |= s<<10-m; + + rx |= rax & MASK5; + ra |= rax>>5*BITS & MASK5; +} + +void +mixmove(int s, int f) +{ + int d; + + if(f == 0) + return; + + d = mval(ri[1], 0, MASK2); + if(d < 0 || d > 4000) + vmerror("Bad address MOVE %d", d); + memcpy(cells+d, cells+s, f*sizeof(u32int)); + d += f; + d &= MASK2; + ri[1] = d < 0 ? -d|SIGNB : d; +} + +u32int +mixld(u32int v, int f) +{ + u32int w; + int a, b, d; + + if(f == 5) + return v; + + UNF(a, b, f); + w = 0; + if(a == 0) { + if(v >> 31) + w = SIGNB; + if(b == 0) + return w; + a++; + } + + d = b - a; + if(a > 5 || b > 5 || d < 0 || d > 4) + vmerror("Bad fpart (%d:%d)", a, b); + v &= mask[d] << (5-b) * BITS; + v >>= (5-b) * BITS; + return w | v; +} + +u32int +mixst(u32int w, u32int v, int f) +{ + int a, b, d; + + if(f == 5) + return v; + + UNF(a, b, f); + if(a == 0) { + w = v>>31 ? w|SIGNB : w&~SIGNB; + if(b == 0) + return w; + a++; + } + + d = b - a; + if(a > 5 || b > 5 || d < 0 || d > 4) + vmerror("Bad fpart (%d:%d)", a, b); + v &= mask[d]; + v <<= (5-b) * BITS; + w &= ~(mask[d] << (5-b)*BITS); + return w | v; +} + +int +mixjbus(int /*m*/, int /*f*/, int ip) +{ + return ip+1; +} + +void +mixioc(int, int f) +{ + switch(f) { + case 18: + case 19: + print("\n"); + break; + } +} + +void mixin(int, int){} + +void +mixout(int m, int f) +{ + switch(f) { + case 18: + mixprint(m, 24); + break; + case 19: + mixprint(m, 14); + break; + } +} + +int +mixjred(int m, int /*f*/, int /*ip*/) +{ + return m; +} + +int +mixjmp(int m, int ip) +{ + ri[0] = ip+1 & MASK2; + return m; +} + +int +mixjov(int m, int ip) +{ + if(ot) { + ot = 0; + ri[0] = ip+1 & MASK2; + return m; + } + return ip + 1; +} + +int +mixjnov(int m, int ip) +{ + if(ot) { + ot = 0; + return ip + 1; + } + ri[0] = ip+1 & MASK2; + return m; +} + +int +mixjc(int m, int ip, int c1, int c2) +{ + if(c1 || c2) { + ri[0] = ip+1 & MASK2; + return m; + } + return ip + 1; +} + +int +mixjaxic(int m, int ip, u32int r, u32int msk, int f) +{ + int v, c; + + v = mval(r, 0, msk); + switch(f) { + default: vmerror("Bad instruction JA condition: %d", f); + case 0: c = v < 0; break; + case 1: c = v == 0; break; + case 2: c = v > 0; break; + case 3: c = v >= 0; break; + case 4: c = v != 0; break; + case 5: c = v <= 0; break; + } + + if(c) { + ri[0] = ip+1 & MASK2; + return m; + } + return ip + 1; +} + +void +mixinc(int m, u32int *r) +{ + int v; + + v = mval(*r, 0, MASK5); + v += m; + *r = v < 0 ? -v|SIGNB : v; +} + +void mixfcmp(void){} + +void +mixcmp(int m, int f, u32int r) +{ + int v1, v2; + + ce = cg = cl = 0; + + v1 = V(r, f); + v2 = V(cells[m], f); + if(v1 < v2) + cl = 1; + else if(v1 > v2) + cg = 1; + else + ce = 1; +} + +int +mixvm(int ip, int once) +{ + u32int r; + int a, i, f, c, m, inst; + + curpc = ip; + for (;;) { + if(curpc < 0 || curpc > 4000) + vmerror("Bad PC %d", curpc); + if(bp[curpc] && !once) + return curpc; + inst = cells[curpc]; + a = V(inst, F(0, 2)); + i = V(inst, F(3, 3)); + f = V(inst, F(4, 4)); + c = V(inst, F(5, 5)); + m = M(a, i); + switch(c) { + default: + fprint(2, "Bad op!\n"); + exits("error"); + case 0: + break; + case 1: + if(f == 6) + mixfadd(inst); + else + mixadd(m, f); + break; + case 2: + if(f == 6) + mixfsub(inst); + else + mixsub(m, f); + break; + case 3: + if(f == 6) + mixfmul(inst); + else + mixmul(m, f); + break; + case 4: + if(f == 6) + mixfdiv(inst); + else + mixdiv(m, f); + break; + case 5: + switch(f) { + default: + vmerror("Bad instruction NUM or CHAR: %d", f); + case 0: + mixnum(); + break; + case 1: + mixchar(); + break; + case 2: + return -1; /* HLT */ + } + break; + case 6: + switch(f) { + default: vmerror("Bad instruction shift: %d", f); + case 0: mixslra(m, 1); break; + case 1: mixslra(m, 0); break; + case 2: mixslrax(m, 1); break; + case 4: mixslrax(m, 0); break; + case 5: mixslc(m); break; + case 6: mixsrc(m); break; + } + break; + case 7: + mixmove(m, f); + break; + case 8: + ra = mixld(cells[m], f); + break; + case 9: case 10: case 11: + case 12: case 13: case 14: + ri[c-8] = mixld(cells[m], f); + break; + case 15: + rx = mixld(cells[m], f); + break; + case 16: + ra = mixld(cells[m], f) ^ SIGNB; + break; + case 17: case 18: case 19: + case 20: case 21: case 22: + ri[c-16] = mixld(cells[m], f) ^ SIGNB; + break; + case 23: + rx = mixld(cells[m], f) ^ SIGNB; + break; + case 24: + cells[m] = mixst(cells[m], ra, f); + break; + case 25: case 26: case 27: + case 28: case 29: case 30: + r = ri[c-24] & ~(MASK3 << 2*BITS); + cells[m] = mixst(cells[m], r, f); + break; + case 31: + cells[m] = mixst(cells[m], rx, f); + break; + case 32: + r = ri[0] & ~(MASK3 << 2*BITS); + cells[m] = mixst(cells[m], r, f); + break; + case 33: + cells[m] = 0; /* STZ */ + break; + case 34: + curpc = mixjbus(m, f, curpc); + goto Again; + case 35: + mixioc(m, f); + break; + case 36: + mixin(m, f); + break; + case 37: + mixout(m, f); + break; + case 38: + curpc = mixjred(m, f, curpc); + break; + case 39: + switch(f) { + default: vmerror("Bad jmp instruction: %d", f); + case 0: curpc = mixjmp(m, curpc); break; + case 1: curpc = m; break; /* JSJ */ + case 2: curpc = mixjov(m, curpc); break; + case 3: curpc = mixjnov(m, curpc); break; + case 4: curpc = mixjc(m, curpc, cl, 0); break; + case 5: curpc = mixjc(m, curpc, ce, 0); break; + case 6: curpc = mixjc(m, curpc, cg, 0); break; + case 7: curpc = mixjc(m, curpc, cg, ce); break; + case 8: curpc = mixjc(m, curpc, cl, cg); break; + case 9: curpc = mixjc(m, curpc, cl, ce); break; + } + goto Again; + case 40: + curpc = mixjaxic(m, curpc, ra, MASK5, f); + goto Again; + case 41: case 42: case 43: + case 44: case 45: case 46: + curpc = mixjaxic(m, curpc, ri[c-40], MASK2, f); + goto Again; + case 47: + curpc = mixjaxic(m, curpc, rx, MASK5, f); + goto Again; + case 48: + switch(f) { + case 0: mixinc(m, &ra); break; + case 1: mixinc(-m, &ra); break; + case 2: + ra = m == 0 + ? inst & SIGNB + : m < 0 ? -m|SIGNB : m; + break; /* ENTA */ + case 3: + ra = m == 0 + ? ~inst & SIGNB + : m > 0 ? m|SIGNB : -m; + break; /* ENNA */ + } + break; + case 49: case 50: case 51: + case 52: case 53: case 54: + switch(f) { + case 0: mixinc(m, ri+(c-48)); break; + case 1: mixinc(-m, ri+(c-48)); break; + case 2: + ri[c-48] = m == 0 + ? inst & SIGNB + : m < 0 ? -m|SIGNB : m; + break; /* ENT[1-6] */ + case 3: + ri[c-48] = m == 0 + ? ~inst & SIGNB + : m > 0 ? m|SIGNB : -m; + break; /* ENN[1-6] */ + } + break; + case 55: + switch(f) { + case 0: mixinc(m, &rx); break; + case 1: mixinc(-m, &rx); break; + case 2: rx = m == 0 + ? inst & SIGNB + : m < 0 ? -m|SIGNB : m; + break; /* ENTX */ + case 3: rx = m == 0 + ? ~inst & SIGNB + : m > 0 ? m|SIGNB : -m; + break; /* ENNX */ + } + break; + case 56: + if(f == 6) + mixfcmp(); + else + mixcmp(m, f, ra); + break; + case 57: case 58: case 59: + case 60: case 61: case 62: + mixcmp(m, f, ri[c-56] & ~(MASK3<<2*BITS)); + break; + case 63: + mixcmp(m, f, rx); + break; + } + curpc++; +Again: + if(once) + return curpc; + } +} diff --git a/sys/src/games/mix/mix.h b/sys/src/games/mix/mix.h new file mode 100644 index 000000000..59e1c70c5 --- /dev/null +++ b/sys/src/games/mix/mix.h @@ -0,0 +1,85 @@ +#pragma varargck type "I" u32int + +typedef struct Sym Sym; +typedef struct Refinst Refinst; +typedef struct Wval Wval; +typedef struct Con Con; + +struct Sym { + Avl; + char *name; + long lex; + union { + struct { + int opc, f; /* LOP LHERE LBACK LFORW */ + }; + u32int mval; /* LSYMDEF */ + struct { + int *refs, i, max; /* LSYMREF */ + }; + }; + char nbuf[1]; +}; + +struct Con { + Sym *sym; + u32int exp; + Con *link; +}; + +int mixvm(int, int); +void repl(int); +u32int mixst(u32int, u32int, int); + +void mixprint(int, int); + +long yylex(void); +int yyparse(void); +void yyerror(char*, ...); +void vmerror(char*, ...); +void skipto(char); +Sym *sym(char*); +void sinit(void); +int asmfile(char*); +int V(u32int, int); +int Ifmt(Fmt*); + +Rune mixtorune(int); +int runetomix(Rune); +void cinit(void); + +void warn(char*, ...); +void *emalloc(ulong); +void *emallocz(ulong); +void *erealloc(void*, ulong); +char *estrdup(char*); +char *strskip(char*); +char *strim(char*); +void *bsearch(void*, void*, long, int, int(*)(void*, void*)); + +Avltree *syms; +int star, line, vmstart, yydone, curpc; +Con *cons; +char *filename; +extern int mask[5]; +u32int cells[4000]; +char bp[4000]; +jmp_buf errjmp; +Biobuf bin; + +u32int ra, rx, ri[7]; +int ce, cl, cg, ot; + +#define F(a, b) 8*(a)+(b) +#define UNF(a, b, f) ((a) = f/8, (b) = f%8) + +enum { + BITS = 6, + MASK1 = 63, + MASK2 = (63<<6) | MASK1, + MASK3 = (63<<12) | MASK2, + MASK4 = (63<<18) | MASK3, + MASK5 = (63<<24) | MASK4, + OVERB = 1<<30, + SIGNB = 1<<31, +}; diff --git a/sys/src/games/mix/mixal.y b/sys/src/games/mix/mixal.y new file mode 100644 index 000000000..34cd31c7f --- /dev/null +++ b/sys/src/games/mix/mixal.y @@ -0,0 +1,359 @@ +%{ +#include <u.h> +#include <libc.h> +#include <avl.h> +#include <bio.h> +#include "mix.h" +%} + +%union { + Sym *sym; + long lval; + u32int mval; + Rune *rbuf; +} + +%type <lval> wval apart exp aexp fpart ipart +%type <mval> wval1 +%type <sym> loc reflit + +%token <sym> LSYMDEF LSYMREF LOP LEQU LORIG LCON LALF LEND +%token <sym> LBACK LHERE LFORW +%token <lval> LNUM +%token <rbuf> LSTR + +%left '+' '-' '*' '/' LSS ':' ',' + +%% + +prog: +| prog inst + +inst: + eol +| loc LOP apart ipart fpart eol + { + defloc($loc, star); + asm($LOP, $apart, $ipart, $fpart); + } +| loc LOP reflit ipart fpart eol + { + defloc($loc, star); + addref($reflit, star); + refasm($LOP, $ipart, $fpart); + } +| loc LEQU wval eol + { + defloc($loc, $wval); + } +| loc LORIG wval eol + { + defloc($loc, star); + star = $wval; + } +| loc LCON wval1 eol + { + defloc($loc, star); + cells[star++] = $wval1; + } +| loc LALF LSTR eol + { + defloc($loc, star); + alf(star++, $LSTR); + } +| loc LEND wval eol + { + endprog($wval); + defloc($loc, star); + } + +loc: + { + $$ = nil; + } +| LSYMREF + { + $$ = $LSYMREF; + } +| LHERE + { + Sym *f; + int l; + + l = ($LHERE)->opc; + back[l] = star; + f = forw + l; + defloc(f, star); + f->lex = LSYMREF; + f->refs = nil; + f->i = f->max = 0; + $$ = nil; + } + +apart: + { + $$ = 0; + } +| exp +| LBACK + { + $$ = back[($LBACK)->opc]; + } + +reflit: + LSYMREF +| '=' wval1 '=' + { + $$ = con($wval1); + } +| LFORW + { + $$ = forw + ($LFORW)->opc; + } + +ipart: + { + $$ = 0; + } +| ',' exp + { + $$ = $exp; + } + +fpart: + { + $$ = -1; + } +| '(' exp ')' + { + if($exp < 0) + yyerror("invalid fpart %d\n", $exp); + $$ = $exp; + } + +exp: + aexp +| '+' aexp + { + $$ = $aexp; + } +| '-' aexp + { + $$ = -$aexp; + } +| exp '+' aexp + { + $$ = $exp + $aexp; + } +| exp '-' aexp + { + $$ = $exp - $aexp; + } +| exp '*' aexp + { + $$ = $exp * $aexp; + } +| exp '/' aexp + { + $$ = ($exp) / $aexp; + } +| exp LSS aexp + { + $$ = (((vlong)$exp) << 30) / $aexp; + } +| exp ':' aexp + { + $$ = F($exp, $aexp); + } + +aexp: + LNUM +| LSYMDEF + { + u32int mval; + + mval = ($LSYMDEF)->mval; + if(mval & SIGNB) { + mval &= ~SIGNB; + $$ = -((long)mval); + } else + $$ = mval; + } +| '*' + { + $$ = star; + } + +wval: + wval1 + { + if($wval1 & SIGNB) + $$ = -(long)($wval1 & MASK5); + else + $$ = $wval1; + } + +wval1: + exp fpart + { + $$ = wval(0, $exp, $fpart); + } +| wval ',' exp fpart + { + $$ = wval($wval, $exp, $fpart); + } + +eol: + '\n' + +%% + +int back[10]; +Sym forw[10]; + +void +defrefs(Sym *sym, long apart) +{ + u32int inst, mval; + int *ref, *ep; + + ep = sym->refs + sym->i; + for(ref = sym->refs; ref < ep; ref++) { + inst = cells[*ref]; + inst &= ~(MASK2 << BITS*3); + if(apart < 0) { + mval = -apart; + inst |= SIGNB; + } else + mval = apart; + inst |= (mval&MASK2) << BITS*3; + cells[*ref] = inst; + } +} + +void +defloc(Sym *sym, long val) +{ + if(sym == nil) + return; + defrefs(sym, val); + free(sym->refs); + sym->lex = LSYMDEF; + sym->mval = val < 0 ? -val|SIGNB : val; +} + +void +addref(Sym *ref, long star) +{ + if(ref->refs == nil || ref->i == ref->max) { + ref->max = ref->max == 0 ? 3 : ref->max*2; + ref->refs = erealloc(ref->refs, ref->max * sizeof(int)); + } + ref->refs[ref->i++] = star; +} + +static void +asm(Sym *op, long apart, long ipart, long fpart) +{ + u32int inst, mval; + + inst = op->opc & MASK1; + + if(fpart == -1) + inst |= (op->f&MASK1) << BITS; + else + inst |= (fpart&MASK1) << BITS; + + inst |= (ipart&MASK1) << BITS*2; + + if(apart < 0) { + mval = -apart; + inst |= SIGNB; + } else + mval = apart; + inst |= (mval&MASK2) << BITS*3; + + cells[star++] = inst; +} + +void +refasm(Sym *op, long ipart, long fpart) +{ + u32int inst; + + inst = op->opc & MASK1; + + if(fpart == -1) + inst |= (op->f&MASK1) << BITS; + else + inst |= (fpart&MASK1) << BITS; + + inst |= (ipart&MASK1) << BITS*2; + + cells[star++] = inst; +} + +Sym* +con(u32int exp) +{ + Con *c; + static int i; + static char buf[20]; + + seprint(buf, buf+20, "con%d\n", i++); + c = emalloc(sizeof(*c)); + c->sym = sym(buf); + c->exp = exp; + c->link = cons; + cons = c; + return c->sym; +} + +void +alf(int loc, Rune *b) +{ + u32int w; + int m; + Rune *r, *e; + + w = 0; + e = b + 5; + for(r = b; r < e; r++) { + if((m = runetomix(*r)) == -1) + yyerror("Bad mixchar %C\n", *r); + w |= m; + if(r+1 < e) + w <<= BITS; + } + cells[loc] = w; +} + +void +endprog(int start) +{ + Con *c, *link; + for(c = cons; c != nil; c = link) { + defloc(c->sym, star); + cells[star++] = c->exp; + link = c->link; + free(c); + } + cons = nil; + vmstart = start; + yydone = 1; +} + +u32int +wval(u32int old, int exp, int f) +{ + if(f == -1) { + if(exp < 0) + return -exp | SIGNB; + else + return exp; + } + + if(exp < 0) + return mixst(old, -exp&MASK5 | SIGNB, f); + return mixst(old, exp & MASK5, f); +} diff --git a/sys/src/games/mix/mkfile b/sys/src/games/mix/mkfile new file mode 100644 index 000000000..750061432 --- /dev/null +++ b/sys/src/games/mix/mkfile @@ -0,0 +1,13 @@ +</$objtype/mkfile + +TARG=mix +YFILES=mixal.y +OFILES=y.tab.$O\ + mix.$O\ + char.$O\ + util.$O\ + repl.$O +HFILES=mix.h y.tab.h +BIN=/$objtype/bin/games + +</sys/src/cmd/mkone diff --git a/sys/src/games/mix/repl.c b/sys/src/games/mix/repl.c new file mode 100644 index 000000000..fa10b2aae --- /dev/null +++ b/sys/src/games/mix/repl.c @@ -0,0 +1,289 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <bio.h> +#include <avl.h> +#include "mix.h" + +int +getf(char *line) +{ + long a, b; + + if(*line == '\0') + return 5; + if(*line++ != '(') + return -1; + a = strtol(line, &line, 10); + if(*line++ != ':') + return -1; + b = strtol(line, &line, 10); + if(*line != ')') + return -1; + return F(a, b); +} + +int +disp(char *line) +{ + int f; + long m; + + if(setjmp(errjmp) == 1) + return -1; + m = strtol(line, &line, 10); + if((f = getf(line)) == -1) + return -1; + print("%d\n", V(cells[m], f)); + return 0; +} + +int +dispreg(char *line) +{ + vlong rax; + char c; + int i, f; + u32int reg; + + if(setjmp(errjmp) == 1) + return -1; + + switch(c = *line++) { + case 'a': + if(*line == 'x') { + rax = ra & MASK5; + rax <<= 5 * BITS; + rax |= rx & MASK5; + if(ra >> 31) + rax = -rax; + print("%lld\n", rax); + return 0; + } else + reg = ra; + break; + case 'x': + reg = rx; + break; + case 'j': + reg = ri[0]; + break; + default: + if(!isdigit(c)) + return -1; + i = c - '0'; + if(i < 1 || i > 6) + return -1; + reg = ri[i]; + } + + if((f = getf(line)) == -1) + return -1; + + print("%d\n", V(reg, f)); + return 0; +} + +int +breakp(char *line) +{ + long l; + + line = strskip(line); + if(!isdigit(*line)) + return -1; + l = strtol(line, nil, 10); + if(l < 0 || l > 4000) + return -1; + bp[l] ^= 1; + return 0; +} + +int +asm(char *l) +{ + char *file; + + if(yydone) { + print("Assembly complete\n"); + return 0; + } + l = strskip(l); + if(*l++ == '<') { + Bterm(&bin); + l = strskip(l); + file = estrdup(strim(l)); + if(asmfile(file) == -1) { + free(file); + return -1; + } + Binit(&bin, 0, OREAD); + free(file); + return 0; + } + + line = 1; + filename = "<stdin>"; + if(setjmp(errjmp) == 0) + yyparse(); + Bterm(&bin); + Binit(&bin, 0, OREAD); + return 0; +} + +int +disasm(char *line) +{ + long l; + + line = strskip(line); + if(!isdigit(*line)) + return -1; + + l = strtol(line, nil, 10); + if(l < 0 || l > 4000) + return -1; + print("%I\n", cells[l]); + return 0; +} + +void +mixprint(int m, int words) +{ + int i; + u32int *wp, w; + Rune buf[6], *rp; + + wp = cells+m; + while(words-- > 0) { + rp = buf; + w = *wp++; + for(i = 4; i > -1; i--) + *rp++ = mixtorune(w>>i*BITS & MASK1); + *rp = '\0'; + print("%S", buf); + } + print("\n"); +} + +int +out(char *line) +{ + long l, i; + + line = strskip(line); + i = 1; + if(*line == '(') { + l = strtol(strskip(line+1), &line, 10); + line = strskip(line); + if(*line != ',') + return -1; + i = strtol(strskip(line+1), &line, 10); + line = strskip(line); + if(*line != ')') + return -1; + } else { + if(!isdigit(*line)) + return -1; + l = strtol(line, nil, 10); + } + mixprint(l, i); + return 0; +} + +void +clearsyms(Sym *s) +{ + if(s == nil) + return; + + clearsyms((Sym*)s->c[0]); + clearsyms((Sym*)s->c[1]); + free(s); +} + +void +repl(int go) +{ + char *line, c; + int len, once; + + + Binit(&bin, 0, OREAD); + + if(go) { + once = 0; + goto Go; + } + + for(;;) { + print("MIX "); + + if((line = Brdline(&bin, '\n')) == nil) + return; + + if((len = Blinelen(&bin)) == 1) + continue; + + line[len-1] = '\0'; + + once = 0; + switch(c = line[0]) { + Err: + print("?\n"); + break; + default: + if(!isdigit(c)) + goto Err; + if(disp(line) == -1) + goto Err; + break; + case 'a': + if(asm(line+1) == -1) + goto Err; + break; + case 'b': + if(breakp(line+1) == -1) + goto Err; + break; + case 'c': + ra = rx = ri[0] = ri[1] = ri[2] = ri[3] = ri[4] = ri[5] = ri[6] = 0; + memset(cells, 0, sizeof(cells)); + vmstart = -1; + yydone = 0; + clearsyms((Sym*)syms->root); + syms->root = nil; + sinit(); + break; + case 'd': + if(disasm(line+1) == -1) + goto Err; + break; + case 'o': + if(out(line+1) == -1) + goto Err; + break; + case 'r': + if(dispreg(line+1) == -1) + goto Err; + break; + case 's': + once = 1; + case 'g': + Go: + if(vmstart == -1) + goto Err; + if(setjmp(errjmp) == 0) + vmstart = mixvm(vmstart, once); + else + break; + if(vmstart == -1) + print("halted\n"); + else + print("at %d:\t%I\n", vmstart, cells[vmstart]); + break; + case 'x': + return; + } + } +} diff --git a/sys/src/games/mix/tests/maximum.m b/sys/src/games/mix/tests/maximum.m new file mode 100644 index 000000000..65c611692 --- /dev/null +++ b/sys/src/games/mix/tests/maximum.m @@ -0,0 +1,14 @@ +# Entry condition R1 = n. +# Exit: RA = max R2 = index of max in X +X EQU 1000 +ORIG 3000 +MAXIMUM STJ EXIT # Subroutine linkage. +INIT ENT3 0,1 # M1. Initialize k ← n. + JMP CHANGEM # j ← n, m ← X[n], k ← n-1. +LOOP CMPA X,3 # M3. Compare. + JGE *+3 # To M5 if m ≥ X[k]. +CHANGEM ENT2 0,3 # M4. Change m. j ← k. + LDA X,3 # m ← X[k]. + DEC3 1 # M5. Decrease k. + J3P LOOP # M2. All tested? To M3 if k > 0. +EXIT JMP * # Return to main program. diff --git a/sys/src/games/mix/tests/maxmain.m b/sys/src/games/mix/tests/maxmain.m new file mode 100644 index 000000000..42c57a67d --- /dev/null +++ b/sys/src/games/mix/tests/maxmain.m @@ -0,0 +1,25 @@ + ORIG X + CON 0 + CON 3910 + CON 23 + CON -45 + CON 310 + CON 475 + CON 40291 + CON 358 + CON 20912 +RESULT ALF "MAX: " + CON 0 + ALF " AT: " + CON 0 + ORIG EXIT+1 +MAIN ENT1 RESULT-X-1 + JMP MAXIMUM + CHAR + STX RESULT+1 + ENTA ,2 + CHAR + STX RESULT+3 + OUT RESULT(19) + HLT + END MAIN diff --git a/sys/src/games/mix/tests/primes.m b/sys/src/games/mix/tests/primes.m new file mode 100644 index 000000000..31b7b86f0 --- /dev/null +++ b/sys/src/games/mix/tests/primes.m @@ -0,0 +1,49 @@ +L EQU 500 +PRINTER EQU 18 +PRIME EQU -1 +BUF0 EQU 2000 +BUF1 EQU BUF0+25 + ORIG 3000 +START IOC 0(PRINTER) + LD1 =1-L= + LD2 =3= +2H INC1 1 + ST2 PRIME+L,1 + J1Z 2F +4H INC2 2 + ENT3 2 +6H ENTA 0 + ENTX 0,2 + DIV PRIME,3 + JXZ 4B + CMPA PRIME,3 + INC3 1 + JG 6B + JMP 2B +2H OUT TITLE(PRINTER) + ENT4 BUF1+10 + ENT5 -50 +2H INC5 L+1 +4H LDA PRIME,5 + CHAR + STX 0,4(1:4) + DEC4 1 + DEC5 50 + J5P 4B + OUT 0,4(PRINTER) + LD4 24,4 + J5N 2B + HLT +ORIG PRIME+1 + CON 2 + ORIG BUF0-5 +TITLE ALF "FIRST" + ALF " FIVE" + ALF " HUND" + ALF "RED P" + ALF "RIMES" + ORIG BUF0+24 + CON BUF1+10 + ORIG BUF1+24 + CON BUF0+10 + END START diff --git a/sys/src/games/mix/util.c b/sys/src/games/mix/util.c new file mode 100644 index 000000000..11ad6226d --- /dev/null +++ b/sys/src/games/mix/util.c @@ -0,0 +1,147 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <avl.h> +#include <bio.h> +#include "mix.h" + +static char buf[1024]; + +char* +strskip(char *s) { + while(isspace(*s)) + s++; + return s; +} + +char* +strim(char *s) +{ + char *t; + + if(*s == '\0') + return s; + + t = s + strlen(s) - 1; + while(isspace(*t) && t > s) + t--; + t[1] = '\0'; + return s; +} + +void +yyerror(char *s, ...) +{ + char *bp; + va_list a; + + bp = seprint(buf, buf+1024, "Assembly error: %s:%d: ", filename, line); + va_start(a, s); + bp = vseprint(bp, buf+1024, s, a); + va_end(a); + *bp++ = '\n'; + write(2, buf, bp - buf); + longjmp(errjmp, 1); +} + +void +vmerror(char *s, ...) +{ + char *bp; + va_list a; + + bp = seprint(buf, buf+1024, "VM error at %d: ", curpc); + va_start(a, s); + bp = vseprint(bp, buf+1024, s, a); + va_end(a); + *bp++ = '\n'; + write(2, buf, bp - buf); + longjmp(errjmp, 1); +} + +void +error(char *s, ...) +{ + char *bp; + va_list a; + + va_start(a, s); + bp = vseprint(buf, buf+1024, s, a); + va_end(a); + *bp++ = '\n'; + write(2, buf, bp - buf); + exits("error"); +} + +void* +emalloc(ulong s) +{ + void *v; + + v = malloc(s); + if(v == nil) + error("Error allocating %lud: %r\n", s); + setmalloctag(v, getcallerpc(&s)); + return v; +} + +void* +emallocz(ulong s) +{ + void *v; + + v = malloc(s); + if(v == nil) + error("Error allocating %lud: %r", s); + memset(v, 0, s); + return v; +} + +void* +erealloc(void *p, ulong s) +{ + void *v; + + v = realloc(p, s); + if(v == nil) + error("Error re-allocating %lud: %r", s); + setrealloctag(v, getcallerpc(&s)); + return v; +} + +char* +estrdup(char *s) +{ + char *n; + + n = strdup(s); + if(n == nil) + error("Error duplicating string %s: %r", s); + setmalloctag(n, getcallerpc(&s)); + return n; +} + +void* +bsearch(void *k, void *a, long n, int w, int (*cmp)(void*, void*)) +{ + void *e; + int c; + + while(n > 0) { + e = (char*)a + w*(n/2); + c = cmp(k, e); + if(c == 0) + return e; + + if(n == 1) + break; + + if(c < 0) + n /= 2; + else { + a = e; + n -= n/2; + } + } + return nil; +} diff --git a/sys/src/games/mkfile b/sys/src/games/mkfile index 3f1dab968..8ec52df05 100644 --- a/sys/src/games/mkfile +++ b/sys/src/games/mkfile @@ -29,6 +29,7 @@ DIRS=\ gba\ mahjongg\ mines\ + mix\ music\ md\ nes\ |