Last active
September 9, 2019 15:43
-
-
Save mischief/75a7b9d4ea97b1dd71b9ac53b6af8b86 to your computer and use it in GitHub Desktop.
wip tis-100
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# To unbundle, run this file | |
echo tis/as.y | |
sed 's/.//' >tis/as.y <<'//GO.SYSIN DD tis/as.y' | |
-%{ | |
-#include <u.h> | |
-#include <libc.h> | |
-#include <bio.h> | |
-#include <ctype.h> | |
- | |
-#include "tis.h" | |
- | |
-enum { | |
- EOF = -1, | |
-}; | |
- | |
-void yyerror(char *, ...); | |
- | |
-typedef struct Label Label; | |
-struct Label | |
-{ | |
- char name[32]; | |
- Reg pc; | |
-}; | |
- | |
-Label labels[32]; | |
-int nlabels; | |
- | |
-uint parsepc; | |
-T21 *curmach; | |
-int line; | |
- | |
-static Reg Z; | |
- | |
-static Op* | |
-pushinst(uchar i, Reg a, Reg b) | |
-{ | |
- Op op; | |
- | |
- op = tis_op(i, a, b); | |
- | |
- if(parsepc >= nelem(curmach->mem)) | |
- yyerror("too many instructions"); | |
- | |
- curmach->mem[parsepc] = op; | |
- curmach->nop++; | |
- parsepc++; | |
- return &curmach->mem[parsepc-1]; | |
-} | |
- | |
-Label* | |
-looklabel(char *s) | |
-{ | |
- int i; | |
- Label *l; | |
- | |
- for(i = 0; i < nlabels; i++){ | |
- l = &labels[i]; | |
- if(strcmp(l->name, s) == 0) | |
- return l; | |
- } | |
- | |
- return nil; | |
-} | |
- | |
-%} | |
- | |
-%union | |
-{ | |
- Label *l; | |
- Reg n; | |
- char target[32]; | |
-} | |
- | |
-%token <n> NUM | |
-%token <l> LABEL | |
-%token <target> TARGET | |
-%token LNOP LMOV LSWP LSAV LADD LSUB LNEG | |
-%token <n> LJMP LJEZ LJNZ LJGZ LJLZ LJRO | |
-%token <n> LACC LBAK LNIL LLEFT LRIGHT LUP LDOWN | |
-%type <n> regimm regreg reg | |
-%type <n> jmp | |
- | |
-%% | |
-start: | |
-| start line | |
- | |
-line: | |
- LABEL | |
-| inst | |
- | |
-inst: | |
- LNOP { pushinst(I_NOP, Z, Z); } | |
-| LMOV regimm ',' regreg { pushinst(I_MOV, $2, $4); } | |
-| LSWP { pushinst(I_SWP, Z, Z); } | |
-| LSAV { pushinst(I_SAV, Z, Z); } | |
-| LADD regimm { pushinst(I_ADD, $2, Z); } | |
-| LSUB regimm { pushinst(I_SUB, $2, Z); } | |
-| LNEG | |
-| jmp TARGET | |
- { | |
- Op *op = pushinst($1.imm, Z, Z); | |
- strcpy(op->label, $2); | |
- } | |
-| LJRO regimm { pushinst(I_JRO, $2, Z); } | |
- | |
-jmp: | |
- LJMP | |
-| LJEZ | |
-| LJNZ | |
-| LJGZ | |
-| LJLZ | |
- | |
-regimm: | |
- NUM | |
-| regreg | |
- | |
-regreg: | |
- reg { $$.isreg = 1; $$.imm = $1.imm; } | |
- | |
-reg: | |
- LACC | |
-| LBAK | |
-| LNIL | |
-| LLEFT | |
-| LRIGHT | |
-| LUP | |
-| LDOWN | |
- | |
-%% | |
- | |
-Biobuf *tisinput; | |
- | |
-static int | |
-fixjmp(T21 *m) | |
-{ | |
- int i; | |
- Op *op; | |
- Label *l; | |
- | |
- for(i = 0; i < m->nop; i++){ | |
- op = &m->mem[i]; | |
- if(op->label[0] == 0) | |
- continue; | |
- | |
- l = looklabel(op->label); | |
- if(l == nil){ | |
- yyerror("unknown label '%s'", op->label); | |
- return -1; | |
- } | |
- | |
- op->a = l->pc; | |
- } | |
- | |
- return 0; | |
-} | |
- | |
-int | |
-tis_parse(T21 *m, Biobuf *in) | |
-{ | |
- line = 1; | |
- parsepc = 0; | |
- nlabels = 0; | |
- m->nop = 0; | |
- | |
- tisinput = in; | |
- curmach = m; | |
- | |
- extern int yyparse(void); | |
- | |
- if(yyparse() != 0) | |
- return -1; | |
- | |
- return fixjmp(m); | |
-} | |
- | |
-static int | |
-getc(void) | |
-{ | |
- return Bgetc(tisinput); | |
-} | |
- | |
-static void | |
-ungetc(int c) | |
-{ | |
- (void)c; | |
- | |
- Bungetc(tisinput); | |
-} | |
- | |
-static void | |
-eatnl(void) | |
-{ | |
- for(;;){ | |
- switch(getc()){ | |
- case '\n': | |
- line++; | |
- case EOF: | |
- return; | |
- } | |
- } | |
-} | |
- | |
-static int | |
-num(char c) | |
-{ | |
- char buf[32]; | |
- char *p = buf; | |
- | |
- *p++ = c; | |
- | |
- for(;;){ | |
- c = getc(); | |
- if(!isdigit(c)){ | |
- ungetc(c); | |
- *p = 0; | |
- yylval.n.isreg = 0; | |
- yylval.n.imm = atoi(buf); | |
- return NUM; | |
- } | |
- *p++ = c; | |
- } | |
-} | |
- | |
-static struct | |
-{ | |
- char *name; | |
- int type; | |
- int imm; | |
-} itab[] = { | |
- "NOP", LNOP, 0, | |
- "MOV", LMOV, 0, | |
- "SWP", LSWP, 0, | |
- "SAV", LSAV, 0, | |
- "ADD", LADD, 0, | |
- "SUB", LSUB, 0, | |
- "NEG", LNEG, 0, | |
- "JMP", LJMP, I_JMP, | |
- "JEZ", LJEZ, I_JEZ, | |
- "JNZ", LJNZ, I_JNZ, | |
- "JGZ", LJGZ, I_JGZ, | |
- "JLZ", LJLZ, I_JLZ, | |
- "JRO", LJRO, I_JRO, | |
- | |
- "ACC", LACC, R_ACC, | |
- "BAK", LBAK, R_BAK, | |
- "NIL", LNIL, R_NIL, | |
- "LEFT", LLEFT, R_LEFT, | |
- "RIGHT", LRIGHT, R_RIGHT, | |
- "UP", LUP, R_UP, | |
- "DOWN", LDOWN, R_DOWN, | |
-}; | |
- | |
-static int | |
-word(char c) | |
-{ | |
- char buf[32]; | |
- char *p; | |
- Label *l; | |
- int i; | |
- | |
- p = buf; | |
- *p++ = c; | |
- | |
- for(;;){ | |
- c = getc(); | |
- if(!isupper(c)){ | |
- *p = 0; | |
- if(c == ':'){ | |
- if(looklabel(buf) != nil) | |
- yyerror("duplicate label '%s'", buf); | |
- | |
- l = &labels[nlabels++]; | |
- if(nlabels > nelem(labels)) | |
- abort(); | |
- snprint(l->name, sizeof(l->name), "%s", buf); | |
- l->pc.imm = parsepc; | |
- yylval.l = l; | |
- return LABEL; | |
- } | |
- ungetc(c); | |
- | |
- for(i = 0; i < nelem(itab); i++){ | |
- if(strcmp(itab[i].name, buf) == 0){ | |
- yylval.n.imm = itab[i].imm; | |
- return itab[i].type; | |
- } | |
- } | |
- | |
- snprint(yylval.target, sizeof(yylval.target), "%s", buf); | |
- return TARGET; | |
- } | |
- | |
- *p++ = c; | |
- } | |
-} | |
- | |
-int | |
-yylex(void) | |
-{ | |
- int c; | |
- | |
-loop: | |
- c = getc(); | |
- switch(c){ | |
- case EOF: | |
- return EOF; | |
- case '#': | |
- eatnl(); | |
- goto loop; | |
- case ' ': | |
- case '\t': | |
- goto loop; | |
- case '\n': | |
- line++; | |
- goto loop; | |
- case ',': | |
- return ','; | |
- default: | |
- if(c == '-' || isdigit(c)) | |
- return num(c); | |
- return word(c); | |
- } | |
-} | |
- | |
-void | |
-yyerror(char *fmt, ...) | |
-{ | |
- char buf[128]; | |
- va_list arg; | |
- | |
- va_start(arg, fmt); | |
- vseprint(buf, buf+sizeof(buf), fmt, arg); | |
- va_end(arg); | |
- | |
- sysfatal("line %d: %s", line, buf); | |
-} | |
//GO.SYSIN DD tis/as.y | |
echo tis/mkfile | |
sed 's/.//' >tis/mkfile <<'//GO.SYSIN DD tis/mkfile' | |
-</$objtype/mkfile | |
- | |
-TARGET=tis | |
-OFILES=tis.$O y.tab.$O test.$O | |
-YFILES=as.y | |
- | |
-</sys/src/cmd/mkone | |
//GO.SYSIN DD tis/mkfile | |
echo tis/prog.txt | |
sed 's/.//' >tis/prog.txt <<'//GO.SYSIN DD tis/prog.txt' | |
-# a test program. | |
-MOV -999, ACC | |
-L: ADD LEFT | |
-JLZ L | |
-MOV ACC, RIGHT | |
//GO.SYSIN DD tis/prog.txt | |
echo tis/test.c | |
sed 's/.//' >tis/test.c <<'//GO.SYSIN DD tis/test.c' | |
-#include <u.h> | |
-#include <libc.h> | |
-#include <bio.h> | |
- | |
-#include "tis.h" | |
- | |
-void | |
-main(int argc, char *argv[]) | |
-{ | |
- int i; | |
- Port *in, *out; | |
- | |
- ARGBEGIN{ | |
- }ARGEND | |
- | |
- tis_init(); | |
- | |
- Biobuf *b = Bfdopen(0, OREAD); | |
- | |
- T21 m; | |
- | |
- memset(&m, 0, sizeof(m)); | |
- m.trace = 1; | |
- | |
- if(tis_parse(&m, b) < 0) | |
- sysfatal("parse: %r"); | |
- | |
- for(i = 0; i < m.nop; i++){ | |
- fprint(2, "%d %I\n", i, m.mem[i]); | |
- } | |
- | |
- int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 999 }; | |
- i = 0; | |
- | |
- in = &m.ports[P_LEFT][P_DIR_IN]; | |
- out = &m.ports[P_RIGHT][P_DIR_OUT]; | |
- | |
- int portv; | |
- portv = 0; | |
- | |
- out->v = &portv; | |
- | |
- while(portv != 45){ | |
- if(in->v == nil && i < nelem(arr)){ | |
- in->v = &arr[i++]; | |
- } | |
- | |
- tis_step(&m); | |
- } | |
- fprint(2, "output: %d\n", portv); | |
-} | |
//GO.SYSIN DD tis/test.c | |
echo tis/tis.c | |
sed 's/.//' >tis/tis.c <<'//GO.SYSIN DD tis/tis.c' | |
-#include <u.h> | |
-#include <libc.h> | |
-#include <bio.h> | |
- | |
-#include "tis.h" | |
- | |
-static char *regnames[] = { | |
-[R_ACC] "ACC", | |
-[R_BAK] "BAK", | |
-[R_NIL] "NIL", | |
-[R_LEFT] "LEFT", | |
-[R_RIGHT] "RIGHT", | |
-[R_UP] "UP", | |
-[R_DOWN] "DOWN", | |
-}; | |
- | |
-int | |
-tis_regfmt(Fmt *fmt) | |
-{ | |
- Reg r; | |
- | |
- r = va_arg(fmt->args, Reg); | |
- | |
- if(r.isreg){ | |
- if(r.imm >= nelem(regnames)) | |
- return fmtprint(fmt, "<unknown register %d>", r.imm); | |
- return fmtprint(fmt, "%s", regnames[r.imm]); | |
- } | |
- | |
- return fmtprint(fmt, "%#04hx", r.imm); | |
-} | |
- | |
-int | |
-tis_instfmt(Fmt *fmt) | |
-{ | |
- Op op; | |
- | |
- op = va_arg(fmt->args, Op); | |
- switch(op.ins){ | |
- case I_NOP: | |
- return fmtprint(fmt, "NOP"); | |
- case I_MOV: | |
- return fmtprint(fmt, "MOV %µ %µ", op.a, op.b); | |
- case I_SWP: | |
- return fmtprint(fmt, "SWP"); | |
- case I_SAV: | |
- return fmtprint(fmt, "SAV"); | |
- case I_ADD: | |
- return fmtprint(fmt, "ADD %µ", op.a); | |
- case I_SUB: | |
- return fmtprint(fmt, "SUB %µ", op.a); | |
- case I_NEG: | |
- return fmtprint(fmt, "NEG"); | |
- case I_JMP: | |
- return fmtprint(fmt, "JMP %µ", op.a); | |
- case I_JEZ: | |
- return fmtprint(fmt, "JEZ %µ", op.a); | |
- case I_JNZ: | |
- return fmtprint(fmt, "JNZ %µ", op.a); | |
- case I_JGZ: | |
- return fmtprint(fmt, "JGZ %µ", op.a); | |
- case I_JLZ: | |
- return fmtprint(fmt, "JLZ %µ", op.a); | |
- case I_JRO: | |
- return fmtprint(fmt, "JRO %µ", op.a); | |
- default: | |
- return fmtprint(fmt, "<unknown instruction %d>", op.ins); | |
- } | |
-} | |
- | |
-void | |
-tis_init(void) | |
-{ | |
- fmtinstall(L'µ', tis_regfmt); | |
- fmtinstall('I', tis_instfmt); | |
-} | |
- | |
-static int | |
-tis_readreg(T21 *m, int r, int *v) | |
-{ | |
- Port *p; | |
- | |
- switch(r){ | |
- case R_ACC: | |
- *v = m->acc; | |
- break; | |
- case R_BAK: | |
- *v = m->bak; | |
- case R_NIL: | |
- *v = 0; | |
- break; | |
- case R_LEFT: | |
- case R_RIGHT: | |
- case R_UP: | |
- case R_DOWN: | |
- p = &m->ports[r - R_LEFT][P_DIR_IN]; | |
- if(p->v == nil) | |
- return -1; | |
- | |
- *v = *p->v; | |
- p->v = nil; | |
- break; | |
- default: abort(); return 0; | |
- } | |
- | |
- return 0; | |
-} | |
- | |
-Op | |
-tis_op(uchar o, Reg a, Reg b) | |
-{ | |
- Op op; | |
- | |
- op.ins = o; | |
- op.a = a; | |
- op.b = b; | |
- | |
- return op; | |
-} | |
- | |
-static Op | |
-tis_fetch(T21 *m) | |
-{ | |
- int pc; | |
- if(m->pc > nelem(m->mem)) | |
- abort(); | |
- | |
- pc = m->pc; | |
- m->pc = (m->pc + 1) % m->nop; | |
- | |
- return m->mem[pc]; | |
-} | |
- | |
-static int | |
-indir(T21 *m, Reg r, int *v) | |
-{ | |
- if(r.isreg) | |
- return tis_readreg(m, r.imm, v); | |
- | |
- *v = r.imm; | |
- return 0; | |
-} | |
- | |
-static int | |
-portwrite(T21 *m, int port, int v) | |
-{ | |
- Port *p; | |
- | |
- p = &m->ports[port][P_DIR_OUT]; | |
- if(p->v == nil) | |
- return -1; | |
- | |
- *p->v = v; | |
- p->v = nil; | |
- return 0; | |
-} | |
- | |
-void | |
-tis_step(T21 *m) | |
-{ | |
- int acc; | |
- uint curpc; | |
- Op op; | |
- | |
- curpc = m->pc; | |
- op = tis_fetch(m); | |
- | |
- if(m->trace) | |
- fprint(2, "pc=%#02x acc=%#0.4hux bak=%#0.4hux %I\n", curpc, m->acc, m->bak, op); | |
- | |
- switch(op.ins){ | |
- case I_NOP: | |
- break; | |
- case I_MOV: | |
- if(m->ptmp == nil && indir(m, op.a, &m->tmp) < 0){ | |
- m->pc = curpc; | |
- break; | |
- } | |
- | |
- m->ptmp = &m->tmp; | |
- | |
- switch(op.b.imm){ | |
- case R_ACC: | |
- m->acc = m->tmp; | |
- break; | |
- case R_NIL: | |
- break; | |
- case R_LEFT: | |
- case R_RIGHT: | |
- case R_UP: | |
- case R_DOWN: | |
- if(portwrite(m, op.b.imm - R_LEFT, m->tmp) < 0) | |
- m->pc = curpc; | |
- return; | |
- | |
- // TODO: any, last | |
- default: | |
- break; | |
- } | |
- m->ptmp = nil; | |
- break; | |
- case I_SWP: | |
- acc = m->acc; | |
- m->acc = m->bak; | |
- m->bak = acc; | |
- break; | |
- case I_SAV: | |
- m->bak = m->acc; | |
- break; | |
- case I_ADD: | |
- if(indir(m, op.a, &acc) < 0) | |
- break; | |
- | |
- m->acc += acc; | |
- break; | |
- case I_SUB: | |
- if(indir(m, op.a, &acc) < 0) | |
- break; | |
- | |
- m->acc -= acc; | |
- break; | |
- case I_NEG: | |
- m->acc = -m->acc; | |
- break; | |
- case I_JMP: | |
-jmp: | |
- m->pc = op.a.imm; | |
- break; | |
- case I_JEZ: | |
- if(m->acc == 0) | |
- goto jmp; | |
- break; | |
- case I_JNZ: | |
- if(m->acc != 0) | |
- goto jmp; | |
- break; | |
- case I_JGZ: | |
- if(m->acc > 0) | |
- goto jmp; | |
- break; | |
- case I_JLZ: | |
- if(m->acc < 0) | |
- goto jmp; | |
- break; | |
- case I_JRO: | |
- if(indir(m, op.a, &acc) < 0) | |
- break; | |
- | |
- m->pc += acc; | |
- break; | |
- default: | |
- abort(); | |
- } | |
-} | |
- | |
-void | |
-tis_run(T21* m) | |
-{ | |
- (void)m; | |
- | |
- for(;;){} | |
-} | |
//GO.SYSIN DD tis/tis.c | |
echo tis/tis.h | |
sed 's/.//' >tis/tis.h <<'//GO.SYSIN DD tis/tis.h' | |
-enum { | |
- I_NOP = 0, | |
- I_MOV, | |
- I_SWP, | |
- I_SAV, | |
- I_ADD, | |
- I_SUB, | |
- I_NEG, | |
- I_JMP, | |
- I_JEZ, | |
- I_JNZ, | |
- I_JGZ, | |
- I_JLZ, | |
- I_JRO, | |
- I_MAX, | |
- | |
- F_REG = 0x8000, | |
- | |
- R_ACC = 0, | |
- R_BAK, | |
- R_NIL, | |
- R_LEFT, | |
- R_RIGHT, | |
- R_UP, | |
- R_ANY, | |
- R_LAST, | |
- R_DOWN, | |
- | |
- P_LEFT = 0, | |
- P_RIGHT, | |
- P_UP, | |
- P_DOWN, | |
- P_MAX, | |
- | |
- P_DIR_IN = 0, | |
- P_DIR_OUT, | |
- P_DIR_MAX, | |
-}; | |
- | |
-typedef struct Reg Reg; | |
-struct Reg { | |
- int imm; | |
- uchar isreg; | |
-}; | |
- | |
-typedef struct Op Op; | |
-struct Op { | |
- char label[32]; | |
- uchar ins; | |
- Reg a, b; | |
-}; | |
- | |
-typedef struct Port Port; | |
-struct Port { | |
- int *v; | |
-}; | |
- | |
-typedef struct T21 T21; | |
-struct T21 { | |
- Op mem[15]; | |
- uint nop; | |
- | |
- uint pc; | |
- int acc; | |
- int bak; | |
- | |
- int tmp, *ptmp; | |
- Port ports[P_MAX][P_DIR_MAX]; | |
- | |
- int trace; | |
-}; | |
- | |
-void tis_init(void); | |
-Op tis_op(uchar, Reg, Reg); | |
- | |
-void tis_step(T21*); | |
-int tis_parse(T21 *m, Biobuf *in); | |
- | |
-#pragma varargck type "µ" Reg | |
-#pragma varargck type "I" Op | |
//GO.SYSIN DD tis/tis.h |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment