Skip to content

Instantly share code, notes, and snippets.

@mischief
Last active September 9, 2019 15:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mischief/75a7b9d4ea97b1dd71b9ac53b6af8b86 to your computer and use it in GitHub Desktop.
Save mischief/75a7b9d4ea97b1dd71b9ac53b6af8b86 to your computer and use it in GitHub Desktop.
wip tis-100
# 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