summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vi
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/vi
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/vi')
-rwxr-xr-xsys/src/cmd/vi/bpt.c129
-rwxr-xr-xsys/src/cmd/vi/cmd.c649
-rwxr-xr-xsys/src/cmd/vi/float.c783
-rwxr-xr-xsys/src/cmd/vi/icache.c18
-rwxr-xr-xsys/src/cmd/vi/mem.c285
-rwxr-xr-xsys/src/cmd/vi/mips.h257
-rwxr-xr-xsys/src/cmd/vi/mkfile28
-rwxr-xr-xsys/src/cmd/vi/run.c869
-rwxr-xr-xsys/src/cmd/vi/special.c444
-rwxr-xr-xsys/src/cmd/vi/stats.c251
-rwxr-xr-xsys/src/cmd/vi/symbols.c96
-rwxr-xr-xsys/src/cmd/vi/syscall.c731
-rwxr-xr-xsys/src/cmd/vi/vi.c507
13 files changed, 5047 insertions, 0 deletions
diff --git a/sys/src/cmd/vi/bpt.c b/sys/src/cmd/vi/bpt.c
new file mode 100755
index 000000000..ff6ef0b4c
--- /dev/null
+++ b/sys/src/cmd/vi/bpt.c
@@ -0,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include <ctype.h>
+#define Extern extern
+#include "mips.h"
+
+void
+dobplist(void)
+{
+ Breakpoint *b;
+ char buf[512];
+
+ for(b = bplist; b; b = b->next) {
+ switch(b->type) {
+ case Instruction:
+ Bprint(bioout, "0x%lux,%d:b %d done, at ", b->addr, b->count, b->done);
+ symoff(buf, sizeof(buf), b->addr, CTEXT);
+ Bprint(bioout, buf);
+ break;
+
+ case Access:
+ Bprint(bioout, "0x%lux,%d:ba %d done, at ", b->addr, b->count, b->done);
+ symoff(buf, sizeof(buf), b->addr, CDATA);
+ Bprint(bioout, buf);
+ break;
+
+ case Read:
+ Bprint(bioout, "0x%lux,%d:br %d done, at ", b->addr, b->count, b->done);
+ symoff(buf, sizeof(buf), b->addr, CDATA);
+ Bprint(bioout, buf);
+ break;
+
+ case Write:
+ Bprint(bioout, "0x%lux,%d:bw %d done, at ", b->addr, b->count, b->done);
+ symoff(buf, sizeof(buf), b->addr, CDATA);
+ Bprint(bioout, buf);
+ break;
+
+ case Equal:
+ Bprint(bioout, "0x%lux,%d:be at ", b->addr, b->count);
+ symoff(buf, sizeof(buf), b->addr, CDATA);
+ Bprint(bioout, buf);
+ break;
+ }
+ Bprint(bioout, "\n");
+ }
+}
+
+void
+breakpoint(char *addr, char *cp)
+{
+ Breakpoint *b;
+ int type;
+
+ cp = nextc(cp);
+ type = Instruction;
+ switch(*cp) {
+ case 'r':
+ membpt++;
+ type = Read;
+ break;
+ case 'a':
+ membpt++;
+ type = Access;
+ break;
+ case 'w':
+ membpt++;
+ type = Write;
+ break;
+ case 'e':
+ membpt++;
+ type = Equal;
+ break;
+ }
+ b = emalloc(sizeof(Breakpoint));
+ b->addr = expr(addr);
+ b->type = type;
+ b->count = cmdcount;
+ b->done = cmdcount;
+
+ b->next = bplist;
+ bplist = b;
+}
+
+void
+delbpt(char *addr)
+{
+ Breakpoint *b, **l;
+ ulong baddr;
+
+ baddr = expr(addr);
+ l = &bplist;
+ for(b = *l; b; b = b->next) {
+ if(b->addr == baddr) {
+ if(b->type != Instruction)
+ membpt++;
+ *l = b->next;
+ free(b);
+ return;
+ }
+ l = &b->next;
+ }
+
+ Bprint(bioout, "no breakpoint\n");
+}
+
+void
+brkchk(ulong addr, int type)
+{
+ Breakpoint *b;
+
+ for(b = bplist; b; b = b->next) {
+ if(b->addr == addr && (b->type&type)) {
+ if(b->type == Equal && getmem_4(addr) == b->count) {
+ count = 1;
+ atbpt = 1;
+ return;
+ }
+ if(--b->done == 0) {
+ b->done = b->count;
+ count = 1;
+ atbpt = 1;
+ return;
+ }
+ }
+ }
+}
diff --git a/sys/src/cmd/vi/cmd.c b/sys/src/cmd/vi/cmd.c
new file mode 100755
index 000000000..f54fe3763
--- /dev/null
+++ b/sys/src/cmd/vi/cmd.c
@@ -0,0 +1,649 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include <ctype.h>
+#define Extern extern
+#include "mips.h"
+
+char buf[128], lastcmd[128];
+char fmt = 'X';
+int width = 60;
+int inc;
+
+ulong expr(char*);
+ulong expr1(char*);
+char* term(char*, ulong*);
+
+char *
+nextc(char *p)
+{
+ while(*p && (*p == ' ' || *p == '\t') && *p != '\n')
+ p++;
+
+ if(*p == '\n')
+ *p = '\0';
+
+ return p;
+}
+
+char *
+numsym(char *addr, ulong *val)
+{
+ char tsym[128], *t;
+ static char *delim = "`'<>/\\@*|-~+-/=?\n";
+ Symbol s;
+ char c;
+
+ t = tsym;
+ while(c = *addr) {
+ if(strchr(delim, c))
+ break;
+ *t++ = c;
+ addr++;
+ }
+ t[0] = '\0';
+
+ if(strcmp(tsym, ".") == 0) {
+ *val = dot;
+ return addr;
+ }
+
+ if(lookup(0, tsym, &s))
+ *val = s.value;
+ else {
+ if(tsym[0] == '#')
+ *val = strtoul(tsym+1, 0, 16);
+ else
+ *val = strtoul(tsym, 0, 0);
+ }
+ return addr;
+}
+
+ulong
+expr(char *addr)
+{
+ ulong t, t2;
+ char op;
+
+ if(*addr == '\0')
+ return dot;
+
+ addr = numsym(addr, &t);
+
+ if(*addr == '\0')
+ return t;
+
+ addr = nextc(addr);
+ op = *addr++;
+ numsym(addr, &t2);
+ switch(op) {
+ default:
+ Bprint(bioout, "expr syntax\n");
+ return 0;
+ case '+':
+ t += t2;
+ break;
+ case '-':
+ t -= t2;
+ break;
+ case '%':
+ t /= t2;
+ break;
+ case '&':
+ t &= t2;
+ break;
+ case '|':
+ t |= t2;
+ break;
+ }
+
+ return t;
+}
+
+int
+buildargv(char *str, char **args, int max)
+{
+ int na = 0;
+
+ while (na < max) {
+ while((*str == ' ' || *str == '\t' || *str == '\n') && *str != '\0')
+ str++;
+
+ if(*str == '\0')
+ return na;
+
+ args[na++] = str;
+ while(!(*str == ' ' || *str == '\t'|| *str == '\n') && *str != '\0')
+ str++;
+
+ if(*str == '\n')
+ *str = '\0';
+
+ if(*str == '\0')
+ break;
+
+ *str++ = '\0';
+ }
+ return na;
+}
+
+void
+colon(char *addr, char *cp)
+{
+ int argc;
+ char *argv[100];
+ char tbuf[512];
+
+ cp = nextc(cp);
+ switch(*cp) {
+ default:
+ Bprint(bioout, "?\n");
+ return;
+ case 'b':
+ breakpoint(addr, cp+1);
+ return;
+
+ case 'd':
+ delbpt(addr);
+ return;
+
+ /* These fall through to print the stopped address */
+ case 'r':
+ reset();
+ argc = buildargv(cp+1, argv, 100);
+ initstk(argc, argv);
+ count = 0;
+ atbpt = 0;
+ run();
+ break;
+ case 'c':
+ count = 0;
+ atbpt = 0;
+ run();
+ break;
+ case 's':
+ cp = nextc(cp+1);
+ count = 0;
+ if(*cp)
+ count = strtoul(cp, 0, 0);
+ if(count == 0)
+ count = 1;
+ atbpt = 0;
+ run();
+ break;
+ }
+
+ dot = reg.pc;
+ Bprint(bioout, "%s at #%lux ", atbpt ? "breakpoint" : "stopped", dot);
+ symoff(tbuf, sizeof(tbuf), dot, CTEXT);
+ Bprint(bioout, tbuf);
+ if(fmt == 'z')
+ printsource(dot);
+
+ Bprint(bioout, "\n");
+}
+
+
+void
+dollar(char *cp)
+{
+ int nr;
+
+ cp = nextc(cp);
+ switch(*cp) {
+ default:
+ Bprint(bioout, "?\n");
+ break;
+
+ case 'c':
+ stktrace(*cp);
+ break;
+
+ case 'C':
+ stktrace(*cp);
+ break;
+
+ case 'b':
+ dobplist();
+ break;
+
+ case 'r':
+ dumpreg();
+ break;
+
+ case 'R':
+ dumpreg();
+
+ case 'f':
+ dumpfreg();
+ break;
+
+ case 'F':
+ dumpdreg();
+ break;
+
+ case 'q':
+ exits(0);
+ break;
+
+ case 'Q':
+ isum();
+ tlbsum();
+ segsum();
+ break;
+
+ case 't':
+ cp++;
+ switch(*cp) {
+ default:
+ Bprint(bioout, "$t[0sicr#]\n");
+ break;
+ case '\0':
+ trace = 1;
+ break;
+ case '0':
+ trace = 0;
+ sysdbg = 0;
+ calltree = 0;
+ break;
+ case 's':
+ sysdbg = 1;
+ break;
+ case 'i':
+ trace = 1;
+ break;
+ case 'c':
+ calltree = 1;
+ break;
+ case 'r':
+ nr = atoi(cp+1);
+ if(nr < 0 || nr > 31) {
+ print("bad register\n");
+ break;
+ }
+ rtrace ^= (1<<nr);
+ print("%.8ux\n", rtrace);
+ break;
+ }
+ break;
+
+ case 'i':
+ cp++;
+ switch(*cp) {
+ default:
+ Bprint(bioout, "$i[itsa]\n");
+ break;
+ case 'i':
+ isum();
+ break;
+ case 't':
+ tlbsum();
+ break;
+ case 's':
+ segsum();
+ break;
+ case 'a':
+ isum();
+ tlbsum();
+ segsum();
+ iprofile();
+ break;
+ case 'p':
+ iprofile();
+ break;
+ }
+ }
+}
+
+int
+pfmt(char fmt, int mem, ulong val)
+{
+ int c, i;
+ Symbol s;
+ char *p, ch, str[1024];
+
+ c = 0;
+ switch(fmt) {
+ default:
+ Bprint(bioout, "bad modifier\n");
+ return 0;
+ case 'o':
+ c = Bprint(bioout, "%-4lo ", mem ? (ushort)getmem_2(dot) : val);
+ inc = 2;
+ break;
+
+ case 'O':
+ c = Bprint(bioout, "%-8lo ", mem ? getmem_4(dot) : val);
+ inc = 4;
+ break;
+
+ case 'q':
+ c = Bprint(bioout, "%-4lo ", mem ? (short)getmem_2(dot) : val);
+ inc = 2;
+ break;
+
+ case 'Q':
+ c = Bprint(bioout, "%-8lo ", mem ? (long)getmem_4(dot) : val);
+ inc = 4;
+ break;
+
+ case 'd':
+ c = Bprint(bioout, "%-5ld ", mem ? (short)getmem_2(dot) : val);
+ inc = 2;
+ break;
+
+
+ case 'D':
+ c = Bprint(bioout, "%-8ld ", mem ? (long)getmem_4(dot) : val);
+ inc = 4;
+ break;
+
+ case 'x':
+ c = Bprint(bioout, "#%-4lux ", mem ? (long)getmem_2(dot) : val);
+ inc = 2;
+ break;
+
+ case 'X':
+ c = Bprint(bioout, "#%-8lux ", mem ? (long)getmem_4(dot) : val);
+ inc = 4;
+ break;
+
+ case 'u':
+ c = Bprint(bioout, "%-5ld ", mem ? (ushort)getmem_2(dot) : val);
+ inc = 2;
+ break;
+
+ case 'U':
+ c = Bprint(bioout, "%-8ld ", mem ? (ulong)getmem_4(dot) : val);
+ inc = 4;
+ break;
+
+ case 'b':
+ c = Bprint(bioout, "%-3ld ", mem ? getmem_b(dot) : val);
+ inc = 1;
+ break;
+
+ case 'c':
+ c = Bprint(bioout, "%c ", (int)(mem ? getmem_b(dot) : val));
+ inc = 1;
+ break;
+
+ case 'C':
+ ch = mem ? getmem_b(dot) : val;
+ if(isprint(ch))
+ c = Bprint(bioout, "%c ", ch);
+ else
+ c = Bprint(bioout, "\\x%.2x ", ch);
+ inc = 1;
+ break;
+
+ case 's':
+ i = 0;
+ while(ch = getmem_b(dot+i))
+ str[i++] = ch;
+ str[i] = '\0';
+ dot += i;
+ c = Bprint(bioout, "%s", str);
+ inc = 0;
+ break;
+
+ case 'S':
+ i = 0;
+ while(ch = getmem_b(dot+i))
+ str[i++] = ch;
+ str[i] = '\0';
+ dot += i;
+ for(p = str; *p; p++)
+ if(isprint(*p))
+ c += Bprint(bioout, "%c", *p);
+ else
+ c += Bprint(bioout, "\\x%.2ux", *p);
+ inc = 0;
+ break;
+
+ case 'Y':
+ p = ctime(mem ? getmem_b(dot) : val);
+ p[30] = '\0';
+ c = Bprint(bioout, "%s", p);
+ inc = 4;
+ break;
+
+ case 'a':
+ symoff(str, sizeof(str), dot, CTEXT);
+ c = Bprint(bioout, str);
+ inc = 0;
+ break;
+
+ case 'e':
+ for (i = 0; globalsym(&s, i); i++)
+ Bprint(bioout, "%-15s #%lux\n", s.name, getmem_4(s.value));
+ inc = 0;
+ break;
+
+ case 'i':
+ inc = _mipscoinst(symmap, dot, str, sizeof(str));
+ if (inc < 0) {
+ Bprint(bioout, "vi: %r\n");
+ return 0;
+ }
+ c = Bprint(bioout, str);
+ break;
+
+ case 'n':
+ c = width+1;
+ inc = 0;
+ break;
+
+ case '-':
+ c = 0;
+ inc = -1;
+ break;
+
+ case '+':
+ c = 0;
+ inc = 1;
+ break;
+
+ case '^':
+ c = 0;
+ if(inc > 0)
+ inc = -inc;
+ break;
+
+ case 'z':
+ if (findsym(dot, CTEXT, &s))
+ Bprint(bioout, " %s() ", s.name);
+ printsource(dot);
+ inc = 0;
+ break;
+ }
+ return c;
+}
+
+void
+eval(char *addr, char *p)
+{
+ ulong val;
+
+ val = expr(addr);
+ p = nextc(p);
+ if(*p == '\0') {
+ p[0] = fmt;
+ p[1] = '\0';
+ }
+ pfmt(*p, 0, val);
+ Bprint(bioout, "\n");
+}
+
+void
+quesie(char *p)
+{
+ int c, count, i;
+ char tbuf[512];
+
+ c = 0;
+ symoff(tbuf, sizeof(tbuf), dot, CTEXT);
+ Bprint(bioout, "%s?\t", tbuf);
+
+ while(*p) {
+ p = nextc(p);
+ if(*p == '"') {
+ for(p++; *p && *p != '"'; p++) {
+ Bputc(bioout, *p);
+ c++;
+ }
+ if(*p)
+ p++;
+ continue;
+ }
+ count = 0;
+ while(*p >= '0' && *p <= '9')
+ count = count*10 + (*p++ - '0');
+ if(count == 0)
+ count = 1;
+ p = nextc(p);
+ if(*p == '\0') {
+ p[0] = fmt;
+ p[1] = '\0';
+ }
+ for(i = 0; i < count; i++) {
+ c += pfmt(*p, 1, 0);
+ dot += inc;
+ if(c > width) {
+ Bprint(bioout, "\n");
+ symoff(tbuf, sizeof(tbuf), dot, CTEXT);
+ Bprint(bioout, "%s?\t", tbuf);
+ c = 0;
+ }
+ }
+ fmt = *p++;
+ p = nextc(p);
+ }
+ Bprint(bioout, "\n");
+}
+
+void
+catcher(void *a, char *msg)
+{
+ USED(a);
+ if(strcmp(msg, "interrupt") != 0)
+ noted(NDFLT);
+
+ count = 1;
+ print("vi\n");
+ noted(NCONT);
+}
+
+void
+setreg(char *addr, char *cp)
+{
+ int rn;
+
+ dot = expr(addr);
+ cp = nextc(cp);
+ if(strcmp(cp, "pc") == 0) {
+ reg.pc = dot;
+ return;
+ }
+ if(strcmp(cp, "sp") == 0) {
+ reg.r[29] = dot;
+ return;
+ }
+ if(strcmp(cp, "mh") == 0) {
+ reg.mhi = dot;
+ return;
+ }
+ if(strcmp(cp, "ml") == 0) {
+ reg.mlo = dot;
+ return;
+ }
+ if(*cp++ == 'r') {
+ rn = strtoul(cp, 0, 10);
+ if(rn > 0 && rn < 32) {
+ reg.r[rn] = dot;
+ return;
+ }
+ }
+ Bprint(bioout, "bad register\n");
+}
+
+void
+cmd(void)
+{
+ char *p, *a, *cp, *gotint;
+ char addr[128];
+ static char *cmdlet = ":$?/=>";
+ int n, i;
+
+ notify(catcher);
+
+ dot = reg.pc;
+ setjmp(errjmp);
+
+ for(;;) {
+ Bflush(bioout);
+ p = buf;
+ n = 0;
+ for(;;) {
+ i = Bgetc(bin);
+ if(i < 0)
+ exits(0);
+ *p++ = i;
+ n++;
+ if(i == '\n')
+ break;
+ }
+
+ if(buf[0] == '\n')
+ strcpy(buf, lastcmd);
+ else {
+ buf[n-1] = '\0';
+ strcpy(lastcmd, buf);
+ }
+ p = buf;
+ a = addr;
+
+ for(;;) {
+ p = nextc(p);
+ if(*p == 0 || strchr(cmdlet, *p))
+ break;
+ *a++ = *p++;
+ }
+
+ *a = '\0';
+ cmdcount = 1;
+ cp = strchr(addr, ',');
+ if(cp != 0) {
+ if(cp[1] == '#')
+ cmdcount = strtoul(cp+2, &gotint, 16);
+ else
+ cmdcount = strtoul(cp+1, &gotint, 0);
+ *cp = '\0';
+ }
+
+ switch(*p) {
+ case '$':
+ dollar(p+1);
+ break;
+ case ':':
+ colon(addr, p+1);
+ break;
+ case '/':
+ case '?':
+ dot = expr(addr);
+ for(i = 0; i < cmdcount; i++)
+ quesie(p+1);
+ break;
+ case '=':
+ eval(addr, p+1);
+ break;
+ case '>':
+ setreg(addr, p+1);
+ break;
+ default:
+ Bprint(bioout, "?\n");
+ break;
+ }
+ }
+}
diff --git a/sys/src/cmd/vi/float.c b/sys/src/cmd/vi/float.c
new file mode 100755
index 000000000..8f1bbaf97
--- /dev/null
+++ b/sys/src/cmd/vi/float.c
@@ -0,0 +1,783 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+void unimp(ulong);
+void Ifcmp(ulong);
+void Ifdiv(ulong);
+void Ifmul(ulong);
+void Ifadd(ulong);
+void Ifsub(ulong);
+void Ifmov(ulong);
+void Icvtd(ulong);
+void Icvtw(ulong);
+void Icvts(ulong);
+void Ifabs(ulong);
+void Ifneg(ulong);
+
+Inst cop1[] = {
+ { Ifadd, "add.f", Ifloat },
+ { Ifsub, "sub.f", Ifloat },
+ { Ifmul, "mul.f", Ifloat },
+ { Ifdiv, "div.f", Ifloat },
+ { unimp, "", },
+ { Ifabs, "abs.f", Ifloat },
+ { Ifmov, "mov.f", Ifloat },
+ { Ifneg, "neg.f", Ifloat },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { Icvts, "cvt.s", Ifloat },
+ { Icvtd, "cvt.d", Ifloat },
+ { unimp, "", },
+ { unimp, "", },
+ { Icvtw, "cvt.w", Ifloat },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { unimp, "", },
+ { Ifcmp, "c.f", Ifloat },
+ { Ifcmp, "c.un", Ifloat },
+ { Ifcmp, "c.eq", Ifloat },
+ { Ifcmp, "c.ueq", Ifloat },
+ { Ifcmp, "c.olt", Ifloat },
+ { Ifcmp, "c.ult", Ifloat },
+ { Ifcmp, "c.ole", Ifloat },
+ { Ifcmp, "c.ule", Ifloat },
+ { Ifcmp, "c,sf", Ifloat },
+ { Ifcmp, "c.ngle",Ifloat },
+ { Ifcmp, "c.seq", Ifloat },
+ { Ifcmp, "c.ngl", Ifloat },
+ { Ifcmp, "c.lt", Ifloat },
+ { Ifcmp, "c.nge", Ifloat },
+ { Ifcmp, "c.le", Ifloat },
+ { Ifcmp, "c.ngt", Ifloat },
+ { 0 }
+};
+
+void
+unimp(ulong inst)
+{
+ print("op %ld\n", inst&0x3f);
+ Bprint(bioout, "Unimplemented floating point Trap IR %.8lux\n", inst);
+ longjmp(errjmp, 0);
+}
+
+void
+inval(ulong inst)
+{
+ Bprint(bioout, "Invalid Operation Exception IR %.8lux\n", inst);
+ longjmp(errjmp, 0);
+}
+
+void
+ifmt(int r)
+{
+ Bprint(bioout, "Invalid Floating Data Format f%d pc 0x%lux\n", r, reg.pc);
+ longjmp(errjmp, 0);
+}
+
+void
+floatop(int dst, int s1, int s2)
+{
+ if(reg.ft[s1] == FPd && s1 != 24)
+ ifmt(s1);
+ if(reg.ft[s2] == FPd && s2 != 24)
+ ifmt(s2);
+ reg.ft[dst] = FPs;
+}
+
+void
+doubop(int dst, int s1, int s2)
+{
+ ulong l;
+
+ if(reg.ft[s1] != FPd) {
+ if(reg.ft[s1] == FPs && s1 != 24)
+ ifmt(s1);
+ l = reg.di[s1];
+ reg.di[s1] = reg.di[s1+1];
+ reg.di[s1+1] = l;
+ reg.ft[s1] = FPd;
+ }
+ if(reg.ft[s2] != FPd) {
+ if(reg.ft[s2] == FPs && s2 != 24)
+ ifmt(s2);
+ l = reg.di[s2];
+ reg.di[s2] = reg.di[s2+1];
+ reg.di[s2+1] = l;
+ reg.ft[s2] = FPd;
+ }
+ reg.ft[dst] = FPd;
+}
+
+void
+Iswc1(ulong inst)
+{
+ int off;
+ ulong l;
+ int rt, rb, ert;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ if(trace)
+ itrace("swc1\tf%d,0x%x(r%d) ea=%lux", rt, off, rb, reg.r[rb]+off);
+
+ ert = rt&~1;
+ if(reg.ft[ert] == FPd) {
+ l = reg.di[ert];
+ reg.di[ert] = reg.di[ert+1];
+ reg.di[ert+1] = l;
+ reg.ft[ert] = FPmemory;
+ }
+ putmem_w(reg.r[rb]+off, reg.di[rt]);
+}
+
+void
+Ifsub(ulong ir)
+{
+ char fmt;
+ int fs, ft, fd;
+
+ Getf3(fs, ft, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, ft);
+ reg.fl[fd] = reg.fl[fs] - reg.fl[ft];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, ft);
+ reg.fd[fd>>1] = reg.fd[fs>>1] - reg.fd[ft>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.di[fd] = reg.di[fs] - reg.di[ft];
+ break;
+ }
+ if(trace)
+ itrace("sub.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
+}
+
+void
+Ifmov(ulong ir)
+{
+ char fmt;
+ int fs, fd;
+
+ Getf2(fs, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ reg.fl[fd] = reg.fl[fs];
+ reg.ft[fd] = reg.ft[fs];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ reg.fd[fd>>1] = reg.fd[fs>>1];
+ reg.ft[fd] = reg.ft[fs];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.di[fd] = reg.di[fs];
+ reg.ft[fd] = reg.ft[fs];
+ break;
+ }
+ if(trace)
+ itrace("mov.%c\tf%d,f%d", fmt, fd, fs);
+}
+
+void
+Ifabs(ulong ir)
+{
+ char fmt;
+ int fs, fd;
+
+ Getf2(fs, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, fs);
+ if(reg.fl[fs] < 0.0)
+ reg.fl[fd] = -reg.fl[fs];
+ else
+ reg.fl[fd] = reg.fl[fs];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, fs);
+ if(reg.fd[fs>>1] < 0.0)
+ reg.fd[fd>>1] = -reg.fd[fs>>1];
+ else
+ reg.fd[fd>>1] = reg.fd[fs>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ if((long)reg.di[fs] < 0)
+ reg.di[fd] = -reg.di[fs];
+ else
+ reg.di[fd] = reg.di[fs];
+ break;
+ }
+ if(trace)
+ itrace("abs.%c\tf%d,f%d", fmt, fd, fs);
+}
+
+void
+Ifneg(ulong ir)
+{
+ char fmt;
+ int fs, fd;
+
+ Getf2(fs, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, fs);
+ reg.fl[fd] = -reg.fl[fs];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, fs);
+ reg.fd[fd>>1] = -reg.fd[fs>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.di[fd] = -reg.di[fs];
+ break;
+ }
+ if(trace)
+ itrace("neg.%c\tf%d,f%d", fmt, fd, fs);
+}
+
+void
+Icvtd(ulong ir)
+{
+ char fmt;
+ int fs, fd;
+
+ Getf2(fs, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fs, fs, fs);
+ reg.fd[fd>>1] = reg.fl[fs];
+ reg.ft[fd] = FPd;
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, fs);
+ reg.fd[fd>>1] = reg.fd[fs>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.fd[fd>>1] = (long)reg.di[fs];
+ reg.ft[fd] = FPd;
+ break;
+ }
+ if(trace)
+ itrace("cvt.d.%c\tf%d,f%d", fmt, fd, fs);
+}
+
+void
+Icvts(ulong ir)
+{
+ char fmt;
+ int fs, fd;
+
+ Getf2(fs, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, fs);
+ reg.fl[fd] = reg.fl[fs];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fs, fs, fs);
+ reg.fl[fd] = reg.fd[fs>>1];
+ reg.ft[fd] = FPs;
+ break;
+ case 4:
+ fmt = 'w';
+ reg.fl[fd] = (long)reg.di[fs];
+ reg.ft[fd] = FPs;
+ break;
+ }
+ if(trace)
+ itrace("cvt.s.%c\tf%d,f%d", fmt, fd, fs);
+}
+
+void
+Icvtw(ulong ir)
+{
+ long v;
+ char fmt;
+ int fs, fd;
+
+ Getf2(fs, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fs, fs, fs);
+ v = reg.fl[fs];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fs, fs, fs);
+ v = reg.fd[fs>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ v = reg.di[fs];
+ break;
+ }
+ reg.di[fd] = v;
+ reg.ft[fd] = FPmemory;
+ if(trace)
+ itrace("cvt.w.%c\tf%d,f%d", fmt, fd, fs);
+}
+
+void
+Ifadd(ulong ir)
+{
+ char fmt;
+ int fs, ft, fd;
+
+ Getf3(fs, ft, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, ft);
+ reg.fl[fd] = reg.fl[fs] + reg.fl[ft];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, ft);
+ reg.fd[fd>>1] = reg.fd[fs>>1] + reg.fd[ft>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.di[fd] = reg.di[fs] + reg.di[ft];
+ break;
+ }
+ if(trace)
+ itrace("add.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
+}
+
+void
+Ifmul(ulong ir)
+{
+ char fmt;
+ int fs, ft, fd;
+
+ Getf3(fs, ft, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, ft);
+ reg.fl[fd] = reg.fl[fs] * reg.fl[ft];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, ft);
+ reg.fd[fd>>1] = reg.fd[fs>>1] * reg.fd[ft>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.di[fd] = reg.di[fs] * reg.di[ft];
+ break;
+ }
+ if(trace)
+ itrace("mul.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
+}
+
+void
+Ifdiv(ulong ir)
+{
+ char fmt;
+ int fs, ft, fd;
+
+ Getf3(fs, ft, fd, ir);
+
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fd, fs, ft);
+ reg.fl[fd] = reg.fl[fs] / reg.fl[ft];
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fd, fs, ft);
+ reg.fd[fd>>1] = reg.fd[fs>>1] / reg.fd[ft>>1];
+ break;
+ case 4:
+ fmt = 'w';
+ reg.di[fd] = reg.di[fs] / reg.di[ft];
+ break;
+ }
+ if(trace)
+ itrace("div.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
+}
+
+void
+Ilwc1(ulong inst)
+{
+ int rt, rb;
+ int off;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ if(trace)
+ itrace("lwc1\tf%d,0x%x(r%d) ea=%lux", rt, off, rb, reg.r[rb]+off);
+
+ reg.di[rt] = getmem_w(reg.r[rb]+off);
+ reg.ft[rt] = FPmemory;
+}
+
+void
+Ibcfbct(ulong inst)
+{
+ int takeit;
+ int off;
+ ulong npc;
+
+ off = (short)(inst&0xffff);
+
+ takeit = 0;
+ npc = reg.pc + (off<<2) + 4;
+ if(inst&(1<<16)) {
+ if(trace)
+ itrace("bc1t\t0x%lux", npc);
+
+ if(reg.fpsr&FP_CBIT)
+ takeit = 1;
+ }
+ else {
+ if(trace)
+ itrace("bc1f\t0x%lux", npc);
+
+ if((reg.fpsr&FP_CBIT) == 0)
+ takeit = 1;
+ }
+
+ if(takeit) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ }
+}
+
+void
+Imtct(ulong ir)
+{
+ int rt, fs;
+
+ SpecialGetrtrd(rt, fs, ir);
+ if(ir&(1<<22)) { /* CT */
+ if(trace)
+ itrace("ctc1\tr%d,f%d", rt, fs);
+ }
+ else { /* MT */
+ if(trace)
+ itrace("mtc1\tr%d,f%d", rt, fs);
+
+ reg.di[fs] = reg.r[rt];
+ reg.ft[fs] = FPmemory;
+ }
+}
+
+void
+Imfcf(ulong ir)
+{
+ int rt, fs;
+
+ SpecialGetrtrd(rt, fs, ir);
+ if(ir&(1<<22)) { /* CF */
+ if(trace)
+ itrace("cfc1\tr%d,f%d", rt, fs);
+ }
+ else { /* MF */
+ if(trace)
+ itrace("mfc1\tr%d,f%d", rt, fs);
+
+ reg.r[rt] = reg.di[fs];
+ }
+}
+
+void
+Icop1(ulong ir)
+{
+ Inst *i;
+
+ switch((ir>>23)&7) {
+ case 0:
+ Imfcf(ir);
+ break;
+ case 1:
+ Imtct(ir);
+ break;
+ case 2:
+ case 3:
+ Ibcfbct(ir);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ i = &cop1[ir&0x3f];
+ i->count++;
+ (*i->func)(ir);
+ }
+}
+
+void
+Ifcmp(ulong ir)
+{
+ char fmt;
+ int fc;
+ int ft, fs;
+
+ SpecialGetrtrd(ft, fs, ir);
+
+ SET(fc);
+ switch((ir>>21)&0xf) {
+ default:
+ unimp(ir);
+ case 0: /* single */
+ fmt = 's';
+ floatop(fs, fs, ft);
+ if(isNaN(reg.fl[fs]) || isNaN(reg.fl[ft])) {
+ fc = FP_U;
+ break;
+ }
+ if(reg.fl[fs] == reg.fl[ft]) {
+ fc = FP_E;
+ break;
+ }
+ if(reg.fl[fs] < reg.fl[ft]) {
+ fc = FP_L;
+ break;
+ }
+ if(reg.fl[fs] > reg.fl[ft]) {
+ fc = FP_G;
+ break;
+ }
+ print("vi: bad in fcmp");
+ break;
+ case 1: /* double */
+ fmt = 'd';
+ doubop(fs, fs, ft);
+ if(isNaN(reg.fd[fs>>1]) || isNaN(reg.fd[ft>>1])) {
+ fc = FP_U;
+ break;
+ }
+ if(reg.fd[fs>>1] == reg.fd[ft>>1]) {
+ fc = FP_E;
+ break;
+ }
+ if(reg.fd[fs>>1] < reg.fd[ft>>1]) {
+ fc = FP_L;
+ break;
+ }
+ if(reg.fd[fs>>1] > reg.fd[ft>>1]) {
+ fc = FP_G;
+ break;
+ }
+ print("vi: bad in fcmp");
+ break;
+ case 4:
+ fmt = 'w';
+ if(reg.di[fs] == reg.di[ft]) {
+ fc = FP_E;
+ break;
+ }
+ if(reg.di[fs] < reg.di[ft]) {
+ fc = FP_L;
+ break;
+ }
+ if(reg.di[fs] > reg.di[ft]) {
+ fc = FP_G;
+ break;
+ }
+ break;
+ }
+
+ reg.fpsr &= ~FP_CBIT;
+ switch(ir&0xf) {
+ case 0:
+ if(trace)
+ itrace("c.f.%c\tf%d,f%d", fmt, fs, ft);
+ break;
+ case 1:
+ if(trace)
+ itrace("c.un.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 2:
+ if(trace)
+ itrace("c.eq.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 3:
+ if(trace)
+ itrace("c.ueq.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E || fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 4:
+ if(trace)
+ itrace("c.lt.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_L)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 5:
+ if(trace)
+ itrace("c.ult.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_L || fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 6:
+ if(trace)
+ itrace("c.le.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E || fc == FP_L)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 7:
+ if(trace)
+ itrace("c.ule.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E || fc == FP_L || fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ break;
+ case 8:
+ if(trace)
+ itrace("c.sf.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ case 9:
+ if(trace)
+ itrace("c.ngle.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_U) {
+ reg.fpsr |= FP_CBIT;
+ inval(ir);
+ }
+ break;
+ case 10:
+ if(trace)
+ itrace("c.seq.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E)
+ reg.fpsr |= FP_CBIT;
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ case 11:
+ if(trace)
+ itrace("c.ngl.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E || fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ case 12:
+ if(trace)
+ itrace("c.lt.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_L)
+ reg.fpsr |= FP_CBIT;
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ case 13:
+ if(trace)
+ itrace("c.nge.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_L || fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ case 14:
+ if(trace)
+ itrace("c.le.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E || fc == FP_L)
+ reg.fpsr |= FP_CBIT;
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ case 15:
+ if(trace)
+ itrace("c.ngt.%c\tf%d,f%d", fmt, fs, ft);
+ if(fc == FP_E || fc == FP_L || fc == FP_U)
+ reg.fpsr |= FP_CBIT;
+ if(fc == FP_U)
+ inval(ir);
+ break;
+ }
+ USED(fmt);
+}
diff --git a/sys/src/cmd/vi/icache.c b/sys/src/cmd/vi/icache.c
new file mode 100755
index 000000000..71e448860
--- /dev/null
+++ b/sys/src/cmd/vi/icache.c
@@ -0,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+void
+icacheinit(void)
+{
+}
+
+void
+updateicache(ulong addr)
+{
+ USED(addr);
+}
+
diff --git a/sys/src/cmd/vi/mem.c b/sys/src/cmd/vi/mem.c
new file mode 100755
index 000000000..9ab40da5d
--- /dev/null
+++ b/sys/src/cmd/vi/mem.c
@@ -0,0 +1,285 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+extern ulong textbase;
+
+ulong
+ifetch(ulong addr)
+{
+ uchar *va;
+
+ if(addr&3) {
+ Bprint(bioout, "Address error (I-fetch) vaddr %.8lux\n", addr);
+ longjmp(errjmp, 0);
+ }
+
+ if(icache.on)
+ updateicache(addr);
+
+ iprof[(addr-textbase)/PROFGRAN]++;
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+
+ return va[0]<<24 | va[1]<<16 | va[2]<<8 | va[3];
+}
+
+ulong
+getmem_4(ulong addr)
+{
+ ulong val;
+ int i;
+
+ val = 0;
+ for(i = 0; i < 4; i++)
+ val = val<<8 | getmem_b(addr++);
+ return val;
+}
+
+ulong
+getmem_2(ulong addr)
+{
+ ulong val;
+
+ val = getmem_b(addr);
+ val = val<<8 | getmem_b(addr+1);
+
+ return val;
+}
+
+ulong
+getmem_w(ulong addr)
+{
+ uchar *va;
+
+ if(addr&3) {
+ Bprint(bioout, "Address error (Load) vaddr %.8lux\n", addr);
+ longjmp(errjmp, 0);
+ }
+ if(membpt)
+ brkchk(addr, Read);
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+
+ return va[0]<<24 | va[1]<<16 | va[2]<<8 | va[3];;
+}
+
+ushort
+getmem_h(ulong addr)
+{
+ uchar *va;
+
+ if(addr&1) {
+ Bprint(bioout, "Address error (Load) vaddr %.8lux\n", addr);
+ longjmp(errjmp, 0);
+ }
+ if(membpt)
+ brkchk(addr, Read);
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+
+ return va[0]<<8 | va[1];
+}
+
+uchar
+getmem_b(ulong addr)
+{
+ uchar *va;
+
+ if(membpt)
+ brkchk(addr, Read);
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+ return va[0];
+}
+
+void
+putmem_w(ulong addr, ulong data)
+{
+ uchar *va;
+
+ if(addr&3) {
+ Bprint(bioout, "Address error (Store) vaddr %.8lux\n", addr);
+ longjmp(errjmp, 0);
+ }
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+
+ va[0] = data>>24;
+ va[1] = data>>16;
+ va[2] = data>>8;
+ va[3] = data;
+ if(membpt)
+ brkchk(addr, Write);
+}
+void
+putmem_b(ulong addr, uchar data)
+{
+ uchar *va;
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+ va[0] = data;
+ if(membpt)
+ brkchk(addr, Write);
+}
+
+void
+putmem_h(ulong addr, short data)
+{
+ uchar *va;
+
+ if(addr&1) {
+ Bprint(bioout, "Address error (Store) vaddr %.8lux\n", addr);
+ longjmp(errjmp, 0);
+ }
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+ va[0] = data>>8;
+ va[1] = data;
+ if(membpt)
+ brkchk(addr, Write);
+}
+
+char *
+memio(char *mb, ulong mem, int size, int dir)
+{
+ int i;
+ char *buf, c;
+
+ if(mb == 0)
+ mb = emalloc(size);
+
+ buf = mb;
+ switch(dir) {
+ default:
+ fatal(0, "memio");
+ case MemRead:
+ while(size--)
+ *mb++ = getmem_b(mem++);
+ break;
+ case MemReadstring:
+ for(;;) {
+ if(size-- == 0) {
+ Bprint(bioout, "memio: user/kernel copy too long for mipsim\n");
+ longjmp(errjmp, 0);
+ }
+ c = getmem_b(mem++);
+ *mb++ = c;
+ if(c == '\0')
+ break;
+ }
+ break;
+ case MemWrite:
+ for(i = 0; i < size; i++)
+ putmem_b(mem++, *mb++);
+ break;
+ }
+ return buf;
+}
+
+void
+dotlb(ulong vaddr)
+{
+ ulong *l, *e;
+
+ vaddr &= ~(BY2PG-1);
+
+ e = &tlb.tlbent[tlb.tlbsize];
+ for(l = tlb.tlbent; l < e; l++)
+ if(*l == vaddr) {
+ tlb.hit++;
+ return;
+ }
+
+ tlb.miss++;
+ tlb.tlbent[lnrand(tlb.tlbsize)] = vaddr;
+}
+
+void*
+vaddr1(ulong addr)
+{
+ Segment *s, *es;
+ int off, foff, l, n;
+ uchar **p, *a;
+
+ if(tlb.on)
+ dotlb(addr);
+
+ es = &memory.seg[Nseg];
+ for(s = memory.seg; s < es; s++) {
+ if(addr >= s->base && addr < s->end) {
+ s->refs++;
+ off = (addr-s->base)/BY2PG;
+ p = &s->table[off];
+ if(*p)
+ return *p;
+ s->rss++;
+ switch(s->type) {
+ default:
+ fatal(0, "vaddr");
+ case Text:
+ *p = emalloc(BY2PG);
+ if(seek(text, s->fileoff+(off*BY2PG), 0) < 0)
+ fatal(1, "vaddr text seek");
+ if(read(text, *p, BY2PG) < 0)
+ fatal(1, "vaddr text read");
+ return *p;
+ case Data:
+ *p = emalloc(BY2PG);
+ foff = s->fileoff+(off*BY2PG);
+ if(seek(text, foff, 0) < 0)
+ fatal(1, "vaddr text seek");
+ n = read(text, *p, BY2PG);
+ if(n < 0)
+ fatal(1, "vaddr text read");
+ if(foff + n > s->fileend) {
+ l = BY2PG - (s->fileend-foff);
+ a = *p+(s->fileend-foff);
+ memset(a, 0, l);
+ }
+ return *p;
+ case Bss:
+ case Stack:
+ *p = emalloc(BY2PG);
+ return *p;
+ }
+ }
+ }
+ return 0;
+}
+
+void*
+vaddr(ulong addr)
+{
+ void *v;
+
+ v = vaddr1(addr);
+ if(v == 0) {
+ Bprint(bioout, "User TLB miss vaddr 0x%.8lux\n", addr);
+ longjmp(errjmp, 0);
+ }
+ return v;
+}
+
+int
+badvaddr(ulong addr, int n)
+{
+ void *v;
+
+ if(addr & (n-1))
+ return 1;
+ v = vaddr1(addr);
+ if(v == 0)
+ return 1;
+ return 0;
+}
diff --git a/sys/src/cmd/vi/mips.h b/sys/src/cmd/vi/mips.h
new file mode 100755
index 000000000..a389f2dcf
--- /dev/null
+++ b/sys/src/cmd/vi/mips.h
@@ -0,0 +1,257 @@
+/*
+ * mipsim.h
+ */
+#include "/mips/include/ureg.h"
+#define USERADDR 0xC0000000
+#define UREGADDR (USERADDR+BY2PG-4-0xA0)
+#define USER_REG(x) (UREGADDR+(ulong)(x))
+#define REGOFF(x) (USER_REG(&((struct Ureg *) 0)->x))
+
+typedef struct Registers Registers;
+typedef struct Segment Segment;
+typedef struct Memory Memory;
+typedef struct Mul Mul;
+typedef struct Mulu Mulu;
+typedef struct Inst Inst;
+typedef struct Icache Icache;
+typedef struct Tlb Tlb;
+typedef struct Breakpoint Breakpoint;
+
+enum
+{
+ Instruction = 1,
+ Read = 2,
+ Write = 4,
+ Access = 2|4,
+ Equal = 4|8,
+};
+
+struct Breakpoint
+{
+ int type; /* Instruction/Read/Access/Write/Equal */
+ ulong addr; /* Place at address */
+ int count; /* To execute count times or value */
+ int done; /* How many times passed through */
+ Breakpoint *next; /* Link to next one */
+};
+
+enum
+{
+ Iload,
+ Istore,
+ Iarith,
+ Ibranch,
+ Ireg,
+ Isyscall,
+ Ifloat,
+};
+
+enum
+{
+ Nmaxtlb = 64,
+};
+
+struct Tlb
+{
+ int on; /* Being updated */
+ int tlbsize; /* Number of entries */
+ ulong tlbent[Nmaxtlb]; /* Virtual address tags */
+ int hit; /* Number of successful tag matches */
+ int miss; /* Number of failed tag matches */
+};
+
+struct Icache
+{
+ int on; /* Turned on */
+ int linesize; /* Line size in bytes */
+ int stall; /* Cache stalls */
+ int *lines; /* Tag array */
+ int* (*hash)(ulong); /* Hash function */
+ char *hashtext; /* What the function looks like */
+};
+
+struct Inst
+{
+ void (*func)(ulong);
+ char *name;
+ int type;
+ int count;
+ int taken;
+ int useddelay;
+};
+
+struct Registers
+{
+ ulong pc;
+ ulong ir;
+ Inst *ip;
+ long r[32];
+ ulong mhi;
+ ulong mlo;
+
+ ulong fpsr;
+ union {
+ double fd[16];
+ float fl[32];
+ ulong di[32];
+ };
+ char ft[32];
+};
+
+enum
+{
+ FPd = 0,
+ FPs,
+ FPmemory,
+};
+#define dreg(r) ((r)>>1)
+
+struct Mulu
+{
+ ulong lo;
+ ulong hi;
+};
+
+struct Mul
+{
+ long lo;
+ long hi;
+};
+
+enum
+{
+ MemRead,
+ MemReadstring,
+ MemWrite,
+};
+
+enum
+{
+ Stack,
+ Text,
+ Data,
+ Bss,
+ Nseg,
+};
+
+struct Segment
+{
+ short type;
+ ulong base;
+ ulong end;
+ ulong fileoff;
+ ulong fileend;
+ int rss;
+ int refs;
+ uchar **table;
+};
+
+struct Memory
+{
+ Segment seg[Nseg];
+};
+
+void fatal(int, char*, ...);
+void run(void);
+void undef(ulong);
+void dumpreg(void);
+void dumpfreg(void);
+void dumpdreg(void);
+void* emalloc(ulong);
+void* erealloc(void*, ulong, ulong);
+void* vaddr(ulong);
+int badvaddr(ulong, int);
+void itrace(char *, ...);
+void segsum(void);
+void Ssyscall(ulong);
+char* memio(char*, ulong, int, int);
+ulong ifetch(ulong);
+ulong getmem_w(ulong);
+ushort getmem_h(ulong);
+void putmem_w(ulong, ulong);
+uchar getmem_b(ulong);
+void putmem_b(ulong, uchar);
+ulong getmem_4(ulong);
+ulong getmem_2(ulong);
+void putmem_h(ulong, short);
+Mul mul(long, long);
+Mulu mulu(ulong, ulong);
+void isum(void);
+void initicache(void);
+void updateicache(ulong addr);
+void tlbsum(void);
+long lnrand(long);
+void randseed(long, long);
+void cmd(void);
+void brkchk(ulong, int);
+void delbpt(char*);
+void breakpoint(char*, char*);
+char* nextc(char*);
+ulong expr(char*);
+void initmap(void);
+void inithdr(int);
+void initstk(int, char**);
+void reset(void);
+void dobplist(void);
+int _mipscoinst(Map*, uvlong, char*, int);
+void procinit(int);
+void printsource(long);
+void printparams(Symbol *, ulong);
+void printlocals(Symbol *, ulong);
+void stktrace(int);
+void iprofile(void);
+
+/* Globals */
+Extern Registers reg;
+Extern Memory memory;
+Extern int text;
+Extern int trace;
+Extern int sysdbg;
+Extern int calltree;
+Extern Inst itab[];
+Extern Inst ispec[];
+Extern Icache icache;
+Extern Tlb tlb;
+Extern int count;
+Extern jmp_buf errjmp;
+Extern Breakpoint *bplist;
+Extern int atbpt;
+Extern int membpt;
+Extern int cmdcount;
+Extern int nopcount;
+Extern ulong dot;
+extern char *file;
+Extern Biobuf *bioout;
+Extern Biobuf *bin;
+Extern ulong *iprof;
+extern int datasize;
+Extern Map *symmap;
+Extern int rtrace;
+
+/* Plan9 Kernel constants */
+#define BY2PG 4096
+#define BY2WD 4
+#define UTZERO 0x1000
+#define STACKTOP 0x80000000
+#define STACKSIZE 0x10000
+
+#define PROFGRAN 4
+/* Opcode decoders */
+#define Getrsrt(s,t,i) s = (i>>21)&0x1f; t = (i>>16)&0x1f;
+#define Getrbrt(b,t,i) b = (i>>21)&0x1f; t = (i>>16)&0x1f;
+#define Get3(s, t, d, i) s = (i>>21)&0x1f; t = (i>>16)&0x1f; d = (i>>11)&0x1f;
+#define Getf3(s, t, d, i) s = (i>>11)&0x1f; t = (i>>16)&0x1f; d = (i>>6)&0x1f;
+#define Getf2(s, d, i) s = (i>>11)&0x1f; d = (i>>6)&0x1f;
+#define SpecialGetrtrd(t, d, i) t = (i>>16)&0x1f; d = (i>>11)&0x1f;
+
+#define INOPINST "nor"
+#define INOP 0x00000027 /* Instruction used as nop */
+#define SIGNBIT 0x80000000
+#define Iexec(ir) {Inst *i; i = &itab[(ir)>>26]; reg.ip = i; i->count++; (*i->func)(ir); }
+#define Statbra() reg.ip->taken++; if(reg.ir != INOP) reg.ip->useddelay++;
+
+#define FP_U 3
+#define FP_L 1
+#define FP_G 2
+#define FP_E 0
+#define FP_CBIT (1<<23)
diff --git a/sys/src/cmd/vi/mkfile b/sys/src/cmd/vi/mkfile
new file mode 100755
index 000000000..c1eb2b896
--- /dev/null
+++ b/sys/src/cmd/vi/mkfile
@@ -0,0 +1,28 @@
+</$objtype/mkfile
+
+TARG=vi
+OFILES=vi.$O\
+ run.$O\
+ special.$O\
+ mem.$O\
+ syscall.$O\
+ stats.$O\
+ icache.$O\
+ symbols.$O\
+ cmd.$O\
+ bpt.$O\
+ float.$O\
+
+HFILES=mips.h\
+
+BIN=/$objtype/bin
+
+UPDATE=\
+ mkfile\
+ $HFILES\
+ ${OFILES:%.$O=%.c}\
+
+</sys/src/cmd/mkone
+
+acid:
+ $CC -a run.c > acid.def
diff --git a/sys/src/cmd/vi/run.c b/sys/src/cmd/vi/run.c
new file mode 100755
index 000000000..bf3883679
--- /dev/null
+++ b/sys/src/cmd/vi/run.c
@@ -0,0 +1,869 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+void Iaddi(ulong);
+void Isw(ulong);
+void Ilui(ulong);
+void Iori(ulong);
+void Ixori(ulong);
+void Ilw(ulong);
+void Ijal(ulong);
+void Ispecial(ulong);
+void Ibeq(ulong);
+void Ibeql(ulong);
+void Iaddiu(ulong);
+void Ilb(ulong);
+void Iandi(ulong);
+void Ij(ulong);
+void Ibne(ulong);
+void Ibnel(ulong);
+void Isb(ulong);
+void Islti(ulong);
+void Ibcond(ulong);
+void Ibgtz(ulong);
+void Ibgtzl(ulong);
+void Ilbu(ulong);
+void Ilhu(ulong);
+void Ish(ulong);
+void Ilh(ulong);
+void Iblez(ulong);
+void Iblezl(ulong);
+void Isltiu(ulong);
+void Iswc1(ulong);
+void Ilwc1(ulong);
+void Icop1(ulong);
+void Ilwl(ulong);
+void Ilwr(ulong);
+void Ill(ulong);
+void Isc(ulong);
+
+Inst itab[] = {
+ { Ispecial, 0 },
+ { Ibcond, "bcond", Ibranch },
+ { Ij, "j", Ibranch },
+ { Ijal, "jal", Ibranch },
+ { Ibeq, "beq", Ibranch },
+ { Ibne, "bne", Ibranch },
+ { Iblez, "blez", Ibranch },
+ { Ibgtz, "bgtz", Ibranch },
+ { Iaddi, "addi", Iarith }, /* 8 */
+ { Iaddiu, "addiu", Iarith },
+ { Islti, "slti", Iarith },
+ { Isltiu, "sltiu", Iarith },
+ { Iandi, "andi", Iarith },
+ { Iori, "ori", Iarith },
+ { Ixori, "xori", Iarith },
+ { Ilui, "lui", Iload }, /* 15 */
+ { undef, "" },
+ { Icop1, "cop1", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { Ibeql, "beql" },
+ { Ibnel, "bnel" },
+ { Iblezl, "blezl" },
+ { Ibgtzl, "bgtzl" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { Ilb, "lb", Iload },
+ { Ilh, "lh", Iload },
+ { Ilwl, "lwl", Iload },
+ { Ilw, "lw", Iload },
+ { Ilbu, "lbu", Iload },
+ { Ilhu, "lhu", Iload },
+ { Ilwr, "lwr", Iload },
+ { undef, "" },
+ { Isb, "sb", Istore },
+ { Ish, "sh", Istore },
+ { undef, "" },
+ { Isw, "sw", Istore }, /* 43 */
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { Ill, "ll", Iload},
+ { Ilwc1, "lwc1", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { Isc, "sc", Istore },
+ { Iswc1, "swc1", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { 0 }
+};
+
+void
+dortrace(void)
+{
+ int i;
+
+ for(i = 0; i < 32; i++)
+ if(rtrace & (1<<i))
+ Bprint(bioout, "R%.2d %.8lux\n", i, reg.r[i]);
+}
+
+void
+run(void)
+{
+ do {
+ reg.r[0] = 0;
+ reg.ir = ifetch(reg.pc);
+ Iexec(reg.ir);
+ reg.pc += 4;
+ if(bplist)
+ brkchk(reg.pc, Instruction);
+ if(rtrace)
+ dortrace();
+Bflush(bioout);
+ }while(--count);
+}
+
+void
+undef(ulong inst)
+{
+
+/*
+ if((reg.ir>>26) == 0)
+ Bprint(bioout, "special=%d,%d table=%d\n",
+ (reg.ir>>3)&0x7, reg.ir&0x7, reg.ir&0x3f);
+ else
+ Bprint(bioout, "code=%d,%d table=%d\n",
+ reg.ir>>29, (reg.ir>>26)&0x7, reg.ir>>26);
+*/
+
+ Bprint(bioout, "Undefined Instruction Trap IR %.8lux\n", inst);
+ longjmp(errjmp, 0);
+}
+
+void
+Iaddi(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = (short)(inst&0xffff);
+
+ if(trace)
+ itrace("addi\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = reg.r[rs] + imm;
+}
+
+void
+Iandi(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = inst&0xffff;
+
+ if(trace)
+ itrace("andi\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = reg.r[rs] & imm;
+}
+
+void
+Isw(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ v = reg.r[rt];
+ if(trace)
+ itrace("sw\tr%d,0x%x(r%d) %lux=%lux",
+ rt, off, rb, reg.r[rb]+off, v);
+
+ putmem_w(reg.r[rb]+off, v);
+}
+
+void
+Isb(ulong inst)
+{
+ int rt, rb;
+ int off;
+ uchar value;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ value = reg.r[rt];
+ if(trace)
+ itrace("sb\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, reg.r[rb]+off, value);
+
+ putmem_b(reg.r[rb]+off, value);
+}
+
+void
+Ish(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ushort value;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ value = reg.r[rt];
+ if(trace)
+ itrace("sh\tr%d,0x%x(r%d) %lux=%lux",
+ rt, off, rb, reg.r[rb]+off, value&0xffff);
+
+ putmem_h(reg.r[rb]+off, value);
+}
+
+void
+Ilui(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ USED(rs);
+ imm = inst<<16;
+
+ if(trace)
+ itrace("lui\tr%d,#0x%x", rt, imm);
+
+ reg.r[rt] = imm;
+}
+
+void
+Iori(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = inst&0xffff;
+
+ if(trace)
+ itrace("ori\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = reg.r[rs] | imm;
+}
+
+void
+Ixori(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = inst&0xffff;
+
+ if(trace)
+ itrace("xori\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = reg.r[rs] ^ imm;
+}
+
+void
+Ilw(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 4))
+ v = getmem_w(va);
+ itrace("lw\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ reg.r[rt] = getmem_w(va);
+}
+
+void
+Ilwl(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 4))
+ v = getmem_w(va & ~3) << ((va & 3) << 3);
+ itrace("lwl\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ v = getmem_w(va & ~3);
+ switch(va & 3) {
+ case 0:
+ reg.r[rt] = v;
+ break;
+ case 1:
+ reg.r[rt] = (v<<8) | (reg.r[rt] & 0xff);
+ break;
+ case 2:
+ reg.r[rt] = (v<<16) | (reg.r[rt] & 0xffff);
+ break;
+ case 3:
+ reg.r[rt] = (v<<24) | (reg.r[rt] & 0xffffff);
+ break;
+ }
+}
+
+void
+Ilwr(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 4))
+ v = getmem_w(va & ~3) << ((va & 3) << 3);
+ itrace("lwr\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ v = getmem_w(va & ~3);
+ switch(va & 3) {
+ case 0:
+ break;
+ case 1:
+ reg.r[rt] = (v>>24) | (reg.r[rt] & 0xffffff00);
+ break;
+ case 2:
+ reg.r[rt] = (v>>16) | (reg.r[rt] & 0xffff0000);
+ break;
+ case 3:
+ reg.r[rt] = (v>>8) | (reg.r[rt] & 0xff000000);
+ break;
+ }
+}
+
+void
+Ilh(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 2))
+ v = (short)getmem_h(va);
+ itrace("lw\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ reg.r[rt] = (short)getmem_h(va);
+}
+
+void
+Ilhu(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 2))
+ v = getmem_h(va) & 0xffff;
+ itrace("lhu\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ reg.r[rt] = getmem_h(va) & 0xffff;
+}
+
+void
+Ilb(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 1))
+ v = (schar)getmem_b(va);
+ itrace("lb\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ reg.r[rt] = (schar)getmem_b(va);
+}
+
+void
+Ilbu(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 1))
+ v = getmem_b(va) & 0xff;
+ itrace("lbu\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ reg.r[rt] = getmem_b(va) & 0xff;
+}
+
+void
+Ijal(ulong inst)
+{
+ ulong npc;
+ Symbol s;
+
+ npc = (reg.pc&0xF0000000)|((inst&0x3FFFFFF)<<2);
+ if(trace)
+ itrace("jal\t0x%lux", npc);
+
+ reg.r[31] = reg.pc+8;
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+
+ if(calltree) {
+ findsym(npc, CTEXT, &s);
+ Bprint(bioout, "%8lux %s(", reg.pc, s.name);
+ printparams(&s, reg.r[29]);
+ Bprint(bioout, "from ");
+ printsource(reg.pc);
+ Bputc(bioout, '\n');
+ }
+
+ reg.pc = npc-4;
+}
+
+void
+Ij(ulong inst)
+{
+ ulong npc;
+
+ npc = (reg.pc&0xF0000000)|((inst&0x3FFFFFF)<<2);
+ if(trace)
+ itrace("j\t0x%lux", npc);
+
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+}
+
+void
+Ibeq(ulong inst)
+{
+ int rt, rs;
+ int off;
+ ulong npc;
+
+ Getrsrt(rs, rt, inst);
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("beq\tr%d,r%d,0x%lux", rs, rt, npc);
+
+ if(reg.r[rs] == reg.r[rt]) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ }
+}
+
+void
+Ibeql(ulong inst)
+{
+ int rt, rs;
+ int off;
+ ulong npc;
+
+ Getrsrt(rs, rt, inst);
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("beq\tr%d,r%d,0x%lux", rs, rt, npc);
+
+ if(reg.r[rs] == reg.r[rt]) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ } else
+ reg.pc += 4;
+}
+
+void
+Ibgtz(ulong inst)
+{
+ int rs;
+ int off;
+ ulong npc, r;
+
+ rs = (inst>>21)&0x1f;
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("bgtz\tr%d,0x%lux", rs, npc);
+
+ r = reg.r[rs];
+ if(!(r&SIGNBIT) && r != 0) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ }
+}
+
+void
+Ibgtzl(ulong inst)
+{
+ int rs;
+ int off;
+ ulong npc, r;
+
+ rs = (inst>>21)&0x1f;
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("bgtz\tr%d,0x%lux", rs, npc);
+
+ r = reg.r[rs];
+ if(!(r&SIGNBIT) && r != 0) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ } else
+ reg.pc += 4;
+}
+
+void
+Iblez(ulong inst)
+{
+ int rs;
+ int off;
+ ulong npc, r;
+
+ rs = (inst>>21)&0x1f;
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("blez\tr%d,0x%lux", rs, npc);
+
+ r = reg.r[rs];
+ if((r&SIGNBIT) || r == 0) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ }
+}
+
+void
+Iblezl(ulong inst)
+{
+ int rs;
+ int off;
+ ulong npc, r;
+
+ rs = (inst>>21)&0x1f;
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("blez\tr%d,0x%lux", rs, npc);
+
+ r = reg.r[rs];
+ if((r&SIGNBIT) || r == 0) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ } else
+ reg.pc += 4;
+}
+
+void
+Ibne(ulong inst)
+{
+ int rt, rs;
+ int off;
+ ulong npc;
+
+ Getrsrt(rs, rt, inst);
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("bne\tr%d,r%d,0x%lux", rs, rt, npc);
+
+ if(reg.r[rs] != reg.r[rt]) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ }
+}
+
+void
+Ibnel(ulong inst)
+{
+ int rt, rs;
+ int off;
+ ulong npc;
+
+ Getrsrt(rs, rt, inst);
+ off = (short)(inst&0xffff);
+
+ npc = reg.pc + (off<<2) + 4;
+ if(trace)
+ itrace("bne\tr%d,r%d,0x%lux", rs, rt, npc);
+
+ if(reg.r[rs] != reg.r[rt]) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ } else
+ reg.pc += 4;
+}
+
+void
+Iaddiu(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = (short)(inst&0xffff);
+
+ if(trace)
+ itrace("addiu\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = reg.r[rs]+imm;
+}
+
+void
+Islti(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = (short)(inst&0xffff);
+
+ if(trace)
+ itrace("slti\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = reg.r[rs] < imm ? 1 : 0;
+}
+
+void
+Isltiu(ulong inst)
+{
+ int rs, rt;
+ int imm;
+
+ Getrsrt(rs, rt, inst);
+ imm = (short)(inst&0xffff);
+
+ if(trace)
+ itrace("sltiu\tr%d,r%d,#0x%x", rt, rs, imm);
+
+ reg.r[rt] = (ulong)reg.r[rs] < (ulong)imm ? 1 : 0;
+}
+
+/* ll and sc are implemented as lw and sw, since we simulate a uniprocessor */
+
+void
+Ill(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v, va;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ va = reg.r[rb]+off;
+
+ if(trace) {
+ v = 0;
+ if(!badvaddr(va, 4))
+ v = getmem_w(va);
+ itrace("ll\tr%d,0x%x(r%d) %lux=%lux", rt, off, rb, va, v);
+ }
+
+ reg.r[rt] = getmem_w(va);
+}
+
+void
+Isc(ulong inst)
+{
+ int rt, rb;
+ int off;
+ ulong v;
+
+ Getrbrt(rb, rt, inst);
+ off = (short)(inst&0xffff);
+
+ v = reg.r[rt];
+ if(trace)
+ itrace("sc\tr%d,0x%x(r%d) %lux=%lux",
+ rt, off, rb, reg.r[rb]+off, v);
+
+ putmem_w(reg.r[rb]+off, v);
+}
+
+enum
+{
+ Bltz = 0,
+ Bgez = 1,
+ Bltzal = 0x10,
+ Bgezal = 0x11,
+ Bltzl = 2,
+ Bgezl = 3,
+ Bltzall = 0x12,
+ Bgezall = 0x13,
+};
+
+static char *sbcond[] =
+{
+ [Bltz] "ltz",
+ [Bgez] "gez",
+ [Bltzal] "ltzal",
+ [Bgezal] "gezal",
+ [Bltzl] "ltzl",
+ [Bgezl] "gezl",
+ [Bltzall] "ltzall",
+ [Bgezall] "gezall",
+};
+
+void
+Ibcond(ulong inst)
+{
+ int rs, bran;
+ int off, doit, likely;
+ ulong npc;
+
+ rs = (inst>>21)&0x1f;
+ bran = (inst>>16)&0x1f;
+ off = (short)(inst&0xffff);
+ doit = 0;
+ likely = 0;
+
+ npc = reg.pc + (off<<2) + 4;
+ switch(bran) {
+ default:
+ Bprint(bioout, "bcond=%d\n", bran);
+ undef(inst);
+ case Bltzl:
+ likely = 1;
+ case Bltz:
+ if(reg.r[rs]&SIGNBIT)
+ doit = 1;
+ break;
+ case Bgezl:
+ likely = 1;
+ case Bgez:
+ if(!(reg.r[rs]&SIGNBIT))
+ doit = 1;
+ break;
+ case Bltzall:
+ likely = 1;
+ case Bltzal:
+ reg.r[31] = reg.pc+8;
+ if(reg.r[rs]&SIGNBIT)
+ doit = 1;
+ break;
+ case Bgezall:
+ likely = 1;
+ case Bgezal:
+ reg.r[31] = reg.pc+8;
+ if(!(reg.r[rs]&SIGNBIT))
+ doit = 1;
+ break;
+ }
+
+ if(trace)
+ itrace("b%s\tr%d,0x%lux", sbcond[bran], rs, npc);
+
+ if(doit) {
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ reg.pc = npc-4;
+ } else
+ if(likely)
+ reg.pc += 4;
+
+}
diff --git a/sys/src/cmd/vi/special.c b/sys/src/cmd/vi/special.c
new file mode 100755
index 000000000..99032f1f4
--- /dev/null
+++ b/sys/src/cmd/vi/special.c
@@ -0,0 +1,444 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+void Snor(ulong);
+void Ssll(ulong);
+void Ssra(ulong);
+void Sslt(ulong);
+void Ssltu(ulong);
+void Sand(ulong);
+void Saddu(ulong);
+void Sadd(ulong);
+void Sjr(ulong);
+void Sor(ulong);
+void Ssubu(ulong);
+void Sjalr(ulong);
+void Sdivu(ulong);
+void Smfhi(ulong);
+void Smflo(ulong);
+void Sxor(ulong);
+void Smult(ulong);
+void Smultu(ulong);
+void Sdiv(ulong);
+void Ssrl(ulong);
+void Ssllv(ulong);
+void Ssrlv(ulong);
+void Ssrav(ulong);
+
+Inst ispec[] =
+{
+ { Ssll, "sll", Iarith },
+ { undef, "" },
+ { Ssrl, "srl", Iarith },
+ { Ssra, "sra", Iarith },
+ { Ssllv, "sllv", Iarith },
+ { undef, "" },
+ { Ssrlv, "srlv", Iarith },
+ { Ssrav, "srav", Iarith },
+ { Sjr, "jr", Ibranch },
+ { Sjalr, "jalr", Ibranch },
+ { undef, "" },
+ { undef, "" },
+ { Ssyscall, "sysc", Isyscall },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { Smfhi, "mfhi", Ireg },
+ { undef, "" },
+ { Smflo, "mflo", Ireg },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { Smult, "mult", Iarith },
+ { Smultu, "multu" },
+ { Sdiv, "div", Iarith },
+ { Sdivu, "divu", Iarith },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { Sadd, "add", Iarith },
+ { Saddu, "addu", Iarith },
+ { undef, "" },
+ { Ssubu, "subu", Iarith },
+ { Sand, "and", Iarith },
+ { Sor, "or", Iarith },
+ { Sxor, "xor", Iarith },
+ { Snor, "nor", Iarith },
+ { undef, "" },
+ { undef, "" },
+ { Sslt, "slt", Iarith },
+ { Ssltu, "sltu", Iarith },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { 0 }
+};
+
+void
+Ispecial(ulong inst)
+{
+ Inst *i;
+
+ i = &ispec[inst&0x3f];
+ reg.ip = i;
+ i->count++;
+ (*i->func)(inst);
+}
+
+void
+Snor(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("nor\tr%d,r%d,r%d", rd, rs, rt);
+
+ if(inst == INOP)
+ nopcount++;
+ else
+ reg.r[rd] = ~(reg.r[rt]|reg.r[rs]);
+}
+
+void
+Ssll(ulong inst)
+{
+ int rd, rt, shamt;
+
+ SpecialGetrtrd(rt, rd, inst);
+ shamt = (inst>>6)&0x1f;
+ if(trace)
+ itrace("sll\tr%d,r%d,%d", rd, rt, shamt);
+
+ reg.r[rd] = reg.r[rt]<<shamt;
+}
+
+void
+Ssllv(ulong inst)
+{
+ int rd, rt, rs;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("sllv\tr%d,r%d,r%d", rd, rt, rs);
+
+ reg.r[rd] = reg.r[rt]<<(reg.r[rs]&0x1f);
+}
+
+void
+Ssrlv(ulong inst)
+{
+ int rd, rt, rs;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("srlv\tr%d,r%d,r%d", rd, rt, rs);
+
+ reg.r[rd] = (ulong)reg.r[rt] >> (reg.r[rs]&0x1f);
+}
+
+void
+Ssrav(ulong inst)
+{
+ int rd, rt, rs, shamt;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("srav\tr%d,r%d,r%d", rd, rt, rs);
+
+ shamt = reg.r[rs]&0x1f;
+ if(shamt != 0 && (reg.r[rt] & SIGNBIT))
+ reg.r[rd] = reg.r[rt]>>shamt | ~((1<<(32-shamt))-1);
+ else
+ reg.r[rd] = reg.r[rt]>>shamt;
+}
+
+void
+Ssrl(ulong inst)
+{
+ int rd, rt, shamt;
+
+ SpecialGetrtrd(rt, rd, inst);
+ shamt = (inst>>6)&0x1f;
+ if(trace)
+ itrace("srl\tr%d,r%d,%d", rd, rt, shamt);
+
+ reg.r[rd] = (ulong)reg.r[rt] >> shamt;
+}
+
+void
+Ssra(ulong inst)
+{
+ int rd, rt, shamt;
+
+ SpecialGetrtrd(rt, rd, inst);
+ shamt = (inst>>6)&0x1f;
+ if(trace)
+ itrace("sra\tr%d,r%d,%d", rd, rt, shamt);
+
+ if(shamt != 0 && (reg.r[rt] & SIGNBIT))
+ reg.r[rd] = reg.r[rt]>>shamt | ~((1<<(32-shamt))-1);
+ else
+ reg.r[rd] = reg.r[rt]>>shamt;
+}
+
+void
+Sslt(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("slt\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] < reg.r[rt] ? 1 : 0;
+}
+
+void
+Ssltu(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("sltu\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = (unsigned)reg.r[rs] < (unsigned)reg.r[rt] ? 1 : 0;
+}
+
+void
+Sand(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("and\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] & reg.r[rt];
+}
+
+void
+Saddu(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("addu\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] + reg.r[rt];
+}
+
+void
+Sadd(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("add\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] + reg.r[rt];
+}
+
+void
+Ssubu(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("subu\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] - reg.r[rt];
+}
+
+void
+Sor(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("or\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] | reg.r[rt];
+}
+
+void
+Sxor(ulong inst)
+{
+ int rs, rt, rd;
+
+ Get3(rs, rt, rd, inst);
+ if(trace)
+ itrace("or\tr%d,r%d,r%d", rd, rs, rt);
+
+ reg.r[rd] = reg.r[rs] ^ reg.r[rt];
+}
+
+void
+Sjr(ulong inst)
+{
+ ulong npc;
+ int rs;
+ Symbol s;
+
+ rs = (inst>>21)&0x1f;
+ npc = reg.r[rs];
+
+ if(trace)
+ itrace("jr\t0x%lux", npc);
+
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+ if(calltree) {
+ if(rs == 31 || rs == 2) {
+ findsym(npc, CTEXT, &s);
+ Bprint(bioout, "%8lux return to %lux %s r1=%lux\n",
+ reg.pc, npc, s.name, reg.r[1]);
+ }
+ }
+ reg.pc = npc-4;
+}
+
+void
+Sjalr(ulong inst)
+{
+ ulong npc;
+ int rs, rd;
+ Symbol s;
+
+ rs = (inst>>21)&0x1f;
+ rd = (inst>>11)&0x1f;
+ npc = reg.r[rs];
+
+ if(trace)
+ itrace("jalr\tr%d,r%d", rd, rs);
+
+ reg.r[rd] = reg.pc+8;
+ /* Do the delay slot */
+ reg.ir = ifetch(reg.pc+4);
+ Statbra();
+ Iexec(reg.ir);
+
+ if(calltree) {
+ findsym(npc, CTEXT, &s);
+ if(rs == 31)
+ Bprint(bioout, "%8lux return to %8lux %s\n",
+ reg.pc, npc, s.name);
+ else {
+ printparams(&s, reg.r[29]);
+ Bputc(bioout, '\n');
+ }
+ }
+
+ reg.pc = npc-4;
+}
+
+void
+Sdivu(ulong inst)
+{
+ int rs, rt;
+
+ Getrsrt(rs,rt,inst);
+ if(trace)
+ itrace("divu\tr%d,r%d", rs, rt);
+
+ reg.mlo = (ulong)reg.r[rs]/(ulong)reg.r[rt];
+ reg.mhi = (ulong)reg.r[rs]%(ulong)reg.r[rt];
+}
+
+void
+Sdiv(ulong inst)
+{
+ int rs, rt;
+
+ Getrsrt(rs,rt,inst);
+ if(trace)
+ itrace("div\tr%d,r%d", rs, rt);
+
+ reg.mlo = reg.r[rs]/reg.r[rt];
+ reg.mhi = reg.r[rs]%reg.r[rt];
+}
+
+void
+Smfhi(ulong inst)
+{
+ int rd;
+
+ rd = (inst>>11)&0x1ff;
+ if(trace)
+ itrace("mfhi\tr%d", rd);
+
+ reg.r[rd] = reg.mhi;
+}
+
+void
+Smflo(ulong inst)
+{
+ int rd;
+
+ rd = (inst>>11)&0x1ff;
+ if(trace)
+ itrace("mflo\tr%d", rd);
+
+ reg.r[rd] = reg.mlo;
+}
+
+void
+Smult(ulong inst)
+{
+ int rs, rt;
+ Mul m;
+
+ Getrsrt(rs,rt,inst);
+ if(trace)
+ itrace("mult\tr%d,r%d", rs,rt);
+
+ m = mul(reg.r[rs], reg.r[rt]);
+ reg.mlo = m.lo;
+ reg.mhi = m.hi;
+}
+
+void
+Smultu(ulong inst)
+{
+ int rs, rt;
+ Mulu m;
+
+ Getrsrt(rs,rt,inst);
+ if(trace)
+ itrace("multu\tr%d,r%d", rs,rt);
+
+ m = mulu(reg.r[rs], reg.r[rt]);
+ reg.mlo = m.lo;
+ reg.mhi = m.hi;
+}
diff --git a/sys/src/cmd/vi/stats.c b/sys/src/cmd/vi/stats.c
new file mode 100755
index 000000000..178111082
--- /dev/null
+++ b/sys/src/cmd/vi/stats.c
@@ -0,0 +1,251 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+#define prof profvi
+#define Percent(num, max) (((num)*100)/(max))
+
+extern Inst itab[], ispec[], cop1[];
+Inst *tables[] = { itab, ispec, cop1, 0 };
+
+void
+isum(void)
+{
+ Inst *i;
+ int total, loads, stores, arith, branch, realarith;
+ int useddelay, taken, mipreg, syscall;
+ int ldsunused, ldsused, ltotal;
+ int pct, j;
+
+ total = 0;
+ loads = 0;
+ stores = 0;
+ arith = 0;
+ branch = 0;
+ useddelay = 0;
+ taken = 0;
+ mipreg = 0;
+ syscall = 0;
+ realarith = 0;
+
+ /* Compute the total so we can have percentages */
+ for(i = itab; i->func; i++)
+ if(i->name && i->count)
+ total += i->count;
+
+ for(i = ispec; i->func; i++) {
+ if(i->name && i->count) {
+ }
+ }
+ /* Compute the total so we can have percentages */
+ for(j = 0; tables[j]; j++) {
+ for(i = tables[j]; i->func; i++) {
+ if(i->name && i->count) {
+ /* Dont count floating point twice */
+ if(strcmp(i->name, "cop1") == 0)
+ i->count = 0;
+ else
+ total += i->count;
+ }
+ }
+ }
+
+ Bprint(bioout, "\nInstruction summary.\n\n");
+
+ for(j = 0; tables[j]; j++) {
+ for(i =tables[j]; i->func; i++) {
+ if(i->name) {
+ /* This is gross */
+ if(strcmp(i->name, INOPINST) == 0)
+ i->count -= nopcount;
+ if(i->count == 0)
+ continue;
+ pct = Percent(i->count, total);
+ if(pct != 0)
+ Bprint(bioout, "%-8ud %3d%% %s\n",
+ i->count, Percent(i->count,
+ total), i->name);
+ else
+ Bprint(bioout, "%-8ud %s\n",
+ i->count, i->name);
+
+
+ switch(i->type) {
+ default:
+ fatal(0, "isum bad stype %d\n", i->type);
+ case Iload:
+ loads += i->count;
+ break;
+ case Istore:
+ stores += i->count;
+ break;
+ case Iarith:
+ arith += i->count;
+ break;
+ case Ibranch:
+ branch += i->count;
+ taken += i->taken;
+ useddelay += i->useddelay;
+ break;
+ case Ireg:
+ mipreg += i->count;
+ break;
+ case Isyscall:
+ syscall += i->count;
+ break;
+ case Ifloat:
+ realarith += i->count;
+ break;
+ }
+
+ }
+ }
+ }
+
+ Bprint(bioout, "\n%-8ud Memory cycles\n", loads+stores+total);
+ Bprint(bioout, "%-8ud %3d%% Instruction cycles\n",
+ total, Percent(total, loads+stores+total));
+ Bprint(bioout, "%-8ud %3d%% Data cycles\n\n",
+ loads+stores, Percent(loads+stores, loads+stores+total));
+
+ Bprint(bioout, "%-8ud %3d%% Stores\n", stores, Percent(stores, total));
+ Bprint(bioout, "%-8ud %3d%% Loads\n", loads, Percent(loads, total));
+
+ /* Delay slots for loads/stores */
+ ldsunused = nopcount-(branch-useddelay);
+ ldsused = loads-ldsunused;
+ ltotal = ldsused + ldsunused;
+ Bprint(bioout, " %-8ud %3d%% Delay slots\n",
+ ldsused, Percent(ldsused, ltotal));
+
+ Bprint(bioout, " %-8ud %3d%% Unused delay slots\n",
+ ldsunused, Percent(ldsunused, ltotal));
+
+ Bprint(bioout, "%-8ud %3d%% Arithmetic\n",
+ arith, Percent(arith, total));
+
+ Bprint(bioout, "%-8ud %3d%% Floating point\n",
+ realarith, Percent(realarith, total));
+
+ Bprint(bioout, "%-8ud %3d%% Mips special register load/stores\n",
+ mipreg, Percent(mipreg, total));
+
+ Bprint(bioout, "%-8ud %3d%% System calls\n",
+ syscall, Percent(syscall, total));
+
+ Bprint(bioout, "%-8ud %3d%% Branches\n",
+ branch, Percent(branch, total));
+
+ Bprint(bioout, " %-8ud %3d%% Branches taken\n",
+ taken, Percent(taken, branch));
+
+ Bprint(bioout, " %-8ud %3d%% Delay slots\n",
+ useddelay, Percent(useddelay, branch));
+
+ Bprint(bioout, " %-8ud %3d%% Unused delay slots\n",
+ branch-useddelay, Percent(branch-useddelay, branch));
+
+ Bprint(bioout, "%-8ud %3d%% Program total delay slots\n",
+ nopcount, Percent(nopcount, total));
+}
+
+void
+tlbsum(void)
+{
+ if(tlb.on == 0)
+ return;
+
+ Bprint(bioout, "\n\nTlb summary\n");
+
+ Bprint(bioout, "\n%-8d User entries\n", tlb.tlbsize);
+ Bprint(bioout, "%-8d Accesses\n", tlb.hit+tlb.miss);
+ Bprint(bioout, "%-8d Tlb hits\n", tlb.hit);
+ Bprint(bioout, "%-8d Tlb misses\n", tlb.miss);
+ Bprint(bioout, "%7d%% Hit rate\n", Percent(tlb.hit, tlb.hit+tlb.miss));
+}
+
+char *stype[] = { "Stack", "Text", "Data", "Bss" };
+
+void
+segsum(void)
+{
+ Segment *s;
+ int i;
+
+ Bprint(bioout, "\n\nMemory Summary\n\n");
+ Bprint(bioout, " Base End Resident References\n");
+ for(i = 0; i < Nseg; i++) {
+ s = &memory.seg[i];
+ Bprint(bioout, "%-5s %.8lux %.8lux %-8d %-8d\n",
+ stype[i], s->base, s->end, s->rss*BY2PG, s->refs);
+ }
+}
+
+typedef struct Prof Prof;
+struct Prof
+{
+ Symbol s;
+ long count;
+};
+Prof prof[5000];
+
+int
+profcmp(void *va, void *vb)
+{
+ Prof *a, *b;
+
+ a = va;
+ b = vb;
+ return b->count - a->count;
+}
+
+void
+iprofile(void)
+{
+ Prof *p, *n;
+ int i, b, e;
+ ulong total;
+ extern ulong textbase;
+
+ i = 0;
+ p = prof;
+ if(textsym(&p->s, i) == 0)
+ return;
+ i++;
+ for(;;) {
+ n = p+1;
+ if(textsym(&n->s, i) == 0)
+ break;
+ b = (p->s.value-textbase)/PROFGRAN;
+ e = (n->s.value-textbase)/PROFGRAN;
+ while(b < e)
+ p->count += iprof[b++];
+ i++;
+ p = n;
+ }
+
+ qsort(prof, i, sizeof(Prof), profcmp);
+
+ total = 0;
+ for(b = 0; b < i; b++)
+ total += prof[b].count;
+
+ Bprint(bioout, " cycles %% symbol file\n");
+ for(b = 0; b < i; b++) {
+ if(prof[b].count == 0)
+ continue;
+
+ Bprint(bioout, "%8ld %3ld.%ld %-15s ",
+ prof[b].count,
+ 100*prof[b].count/total,
+ (1000*prof[b].count/total)%10,
+ prof[b].s.name);
+
+ printsource(prof[b].s.value);
+ Bputc(bioout, '\n');
+ }
+ memset(prof, 0, sizeof(Prof)*i);
+}
diff --git a/sys/src/cmd/vi/symbols.c b/sys/src/cmd/vi/symbols.c
new file mode 100755
index 000000000..e3f885352
--- /dev/null
+++ b/sys/src/cmd/vi/symbols.c
@@ -0,0 +1,96 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+#define STRINGSZ 128
+
+/*
+ * print the value of dot as file:line
+ */
+void
+printsource(long dot)
+{
+ char str[STRINGSZ];
+
+ if (fileline(str, STRINGSZ, dot))
+ Bprint(bioout, "%s", str);
+}
+
+void
+printlocals(Symbol *fn, ulong fp)
+{
+ int i;
+ Symbol s;
+
+ s = *fn;
+ for (i = 0; localsym(&s, i); i++) {
+ if (s.class != CAUTO)
+ continue;
+ Bprint(bioout, "\t%s=#%lux\n", s.name, getmem_4(fp-s.value));
+ }
+}
+
+void
+printparams(Symbol *fn, ulong fp)
+{
+ int i;
+ Symbol s;
+ int first;
+
+ fp += mach->szreg; /* skip saved pc */
+ s = *fn;
+ for (first = i = 0; localsym(&s, i); i++) {
+ if (s.class != CPARAM)
+ continue;
+ if (first++)
+ Bprint(bioout, ", ");
+ Bprint(bioout, "%s=#%lux", s.name, getmem_4(fp+s.value));
+ }
+ Bprint(bioout, ") ");
+}
+#define STARTSYM "_main"
+#define FRAMENAME ".frame"
+
+void
+stktrace(int modif)
+{
+ ulong pc, sp;
+ Symbol s, f;
+ int i;
+ char buf[512];
+
+ pc = reg.pc;
+ sp = reg.r[29];
+ i = 0;
+ while (findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0) {
+ Bprint(bioout, "%s() at #%llux\n", s.name, s.value);
+ break;
+ }
+ if (pc == s.value) /* at first instruction */
+ f.value = 0;
+ else if (findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+ if (s.type == 'L' || s.type == 'l' || pc <= s.value+4)
+ pc = reg.r[31];
+ else pc = getmem_4(sp);
+ sp += f.value;
+ Bprint(bioout, "%s(", s.name);
+ printparams(&s, sp);
+ printsource(s.value);
+ Bprint(bioout, " called from ");
+ symoff(buf, sizeof(buf), pc-8, CTEXT);
+ Bprint(bioout, buf);
+ printsource(pc-8);
+ Bprint(bioout, "\n");
+ if(modif == 'C')
+ printlocals(&s, sp);
+ if(++i > 40){
+ Bprint(bioout, "(trace truncated)\n");
+ break;
+ }
+ }
+}
diff --git a/sys/src/cmd/vi/syscall.c b/sys/src/cmd/vi/syscall.c
new file mode 100755
index 000000000..7b977dd0d
--- /dev/null
+++ b/sys/src/cmd/vi/syscall.c
@@ -0,0 +1,731 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "mips.h"
+
+#define REGSP 29
+#define REGRET 1
+
+#define ODIRLEN 116 /* compatibility; used in _stat etc. */
+#define OERRLEN 64 /* compatibility; used in _stat etc. */
+
+char errbuf[ERRMAX];
+ulong nofunc;
+
+#include "/sys/src/libc/9syscall/sys.h"
+
+char *sysctab[]={
+ [SYSR1] "SYSR1",
+ [_ERRSTR] "_errstr",
+ [BIND] "Bind",
+ [CHDIR] "Chdir",
+ [CLOSE] "Close",
+ [DUP] "Dup",
+ [ALARM] "Alarm",
+ [EXEC] "Exec",
+ [EXITS] "Exits",
+ [_FSESSION] "_Fsession",
+ [FAUTH] "Fauth",
+ [_FSTAT] "_fstat",
+ [SEGBRK] "Segbrk",
+ [_MOUNT] "_Mount",
+ [OPEN] "Open",
+ [_READ] "_Read",
+ [OSEEK] "Oseek",
+ [SLEEP] "Sleep",
+ [_STAT] "_Stat",
+ [RFORK] "Rfork",
+ [_WRITE] "_Write",
+ [PIPE] "Pipe",
+ [CREATE] "Create",
+ [FD2PATH] "Fd2path",
+ [BRK_] "Brk_",
+ [REMOVE] "Remove",
+ [_WSTAT] "_Wstat",
+ [_FWSTAT] "_Fwstat",
+ [NOTIFY] "Notify",
+ [NOTED] "Noted",
+ [SEGATTACH] "Segattach",
+ [SEGDETACH] "Segdetach",
+ [SEGFREE] "Segfree",
+ [SEGFLUSH] "Segflush",
+ [RENDEZVOUS] "Rendezvous",
+ [UNMOUNT] "Unmount",
+ [_WAIT] "Wait",
+ [SEEK] "Seek",
+ [FVERSION] "Fversion",
+ [ERRSTR] "Errstr",
+ [STAT] "Stat",
+ [FSTAT] "Fstat",
+ [WSTAT] "Wstat",
+ [FWSTAT] "Fwstat",
+ [MOUNT] "Mount",
+ [AWAIT] "Await",
+ [PREAD] "Pread",
+ [PWRITE] "Pwrite",
+};
+
+void sys1(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+
+void
+sys_errstr(void)
+{
+ ulong str;
+
+ str = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("errstr(0x%lux)", str);
+
+ memio(errbuf, str, OERRLEN, MemWrite);
+ strcpy(errbuf, "no error");
+ reg.r[REGRET] = 0;
+
+}
+
+void
+syserrstr(void)
+{
+ ulong str;
+ uint n;
+
+ str = getmem_w(reg.r[REGSP]+4);
+ n = getmem_w(reg.r[REGSP]+8);
+ if(sysdbg)
+ itrace("errstr(0x%lux, 0x%lux)", str, n);
+
+ if(n > strlen(errbuf)+1)
+ n = strlen(errbuf)+1;
+ memio(errbuf, str, n, MemWrite);
+ strcpy(errbuf, "no error");
+ reg.r[REGRET] = n;
+
+}
+
+void
+sysfd2path(void)
+{
+ int n;
+ uint fd;
+ ulong str;
+ char buf[1024];
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ str = getmem_w(reg.r[REGSP]+8);
+ n = getmem_w(reg.r[REGSP]+12);
+ if(sysdbg)
+ itrace("fd2path(0x%lux, 0x%lux, 0x%lux)", fd, str, n);
+ reg.r[REGRET] = -1;
+ if(n > sizeof buf){
+ strcpy(errbuf, "buffer too big");
+ return;
+ }
+ n = fd2path(fd, buf, sizeof buf);
+ if(n < 0)
+ errstr(buf, sizeof buf);
+ else
+ memio(errbuf, str, n, MemWrite);
+ reg.r[REGRET] = n;
+
+}
+
+void
+sysbind(void)
+{
+ ulong pname, pold, flags;
+ char name[1024], old[1024];
+ int n;
+
+ pname = getmem_w(reg.r[REGSP]+4);
+ pold = getmem_w(reg.r[REGSP]+8);
+ flags = getmem_w(reg.r[REGSP]+12);
+ memio(name, pname, sizeof(name), MemReadstring);
+ memio(old, pold, sizeof(old), MemReadstring);
+ if(sysdbg)
+ itrace("bind(0x%lux='%s', 0x%lux='%s', 0x%lux)", name, name, old, old, flags);
+
+ n = bind(name, old, flags);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+syschdir(void)
+{
+ char file[1024];
+ int n;
+ ulong name;
+
+ name = getmem_w(reg.r[REGSP]+4);
+ memio(file, name, sizeof(file), MemReadstring);
+ if(sysdbg)
+ itrace("chdir(0x%lux='%s', 0x%lux)", name, file);
+
+ n = chdir(file);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sysclose(void)
+{
+ int n;
+ ulong fd;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("close(%d)", fd);
+
+ n = close(fd);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ reg.r[REGRET] = n;
+}
+
+void
+sysdup(void)
+{
+ int oldfd, newfd;
+ int n;
+
+ oldfd = getmem_w(reg.r[REGSP]+4);
+ newfd = getmem_w(reg.r[REGSP]+8);
+ if(sysdbg)
+ itrace("dup(%d, %d)", oldfd, newfd);
+
+ n = dup(oldfd, newfd);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ reg.r[REGRET] = n;
+}
+
+void
+sysexits(void)
+{
+ char buf[OERRLEN];
+ ulong str;
+
+ str = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("exits(0x%lux)", str);
+
+ count = 1;
+ if(str != 0) {
+ memio(buf, str, sizeof buf, MemRead);
+ Bprint(bioout, "exits(%s)\n", buf);
+ }
+ else
+ Bprint(bioout, "exits(0)\n");
+}
+
+void
+sysopen(void)
+{
+ char file[1024];
+ int n;
+ ulong mode, name;
+
+ name = getmem_w(reg.r[REGSP]+4);
+ mode = getmem_w(reg.r[REGSP]+8);
+ memio(file, name, sizeof(file), MemReadstring);
+ if(sysdbg)
+ itrace("open(0x%lux='%s', 0x%lux)", name, file, mode);
+
+ n = open(file, mode);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ reg.r[REGRET] = n;
+};
+
+void
+sysread(vlong offset)
+{
+ int fd;
+ ulong size, a;
+ char *buf, *p;
+ int n, cnt, c;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ a = getmem_w(reg.r[REGSP]+8);
+ size = getmem_w(reg.r[REGSP]+12);
+
+ buf = emalloc(size);
+ if(fd == 0) {
+ print("\nstdin>>");
+ p = buf;
+ n = 0;
+ cnt = size;
+ while(cnt) {
+ c = Bgetc(bin);
+ if(c <= 0)
+ break;
+ *p++ = c;
+ n++;
+ cnt--;
+ if(c == '\n')
+ break;
+ }
+ }
+ else
+ n = pread(fd, buf, size, offset);
+
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ else
+ memio(buf, a, n, MemWrite);
+
+ if(sysdbg)
+ itrace("read(%d, 0x%lux, %d, 0x%llx) = %d", fd, a, size, offset, n);
+
+ free(buf);
+ reg.r[REGRET] = n;
+}
+
+void
+sys_read(void)
+{
+ sysread(-1LL);
+}
+
+void
+syspread(void)
+{
+ union {
+ vlong v;
+ ulong u[2];
+ } o;
+
+ o.u[0] = getmem_w(reg.r[REGSP]+16);
+ o.u[1] = getmem_w(reg.r[REGSP]+20);
+ sysread(o.v);
+}
+
+void
+sysseek(void)
+{
+ int fd;
+ ulong mode;
+ ulong retp;
+ union {
+ vlong v;
+ ulong u[2];
+ } o;
+
+ retp = getmem_w(reg.r[REGSP]+4);
+ fd = getmem_w(reg.r[REGSP]+8);
+ o.u[0] = getmem_w(reg.r[REGSP]+12);
+ o.u[1] = getmem_w(reg.r[REGSP]+16);
+ mode = getmem_w(reg.r[REGSP]+20);
+ if(sysdbg)
+ itrace("seek(%d, %lld, %d)", fd, o.v, mode);
+
+ o.v = seek(fd, o.v, mode);
+ if(o.v < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ memio((char*)o.u, retp, sizeof(vlong), MemWrite);
+}
+
+void
+sysoseek(void)
+{
+ int fd, n;
+ ulong off, mode;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ off = getmem_w(reg.r[REGSP]+8);
+ mode = getmem_w(reg.r[REGSP]+12);
+ if(sysdbg)
+ itrace("seek(%d, %lud, %d)", fd, off, mode);
+
+ n = seek(fd, off, mode);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sysrfork(void)
+{
+ int flag;
+
+ flag = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("rfork(%d)", flag);
+ if(flag & RFPROC) {
+ Bprint(bioout, "rfork: cannot create process, rfork(0x%.8ux)\n", flag);
+ exits(0);
+ }
+ reg.r[REGRET] = rfork(flag);
+}
+
+void
+syssleep(void)
+{
+ ulong len;
+ int n;
+
+ len = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("sleep(%d)", len);
+
+ n = sleep(len);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sys_stat(void)
+{
+ char nambuf[1024];
+ char buf[ODIRLEN];
+ ulong edir, name;
+ extern int _stat(char*, char*); /* old system call */
+ int n;
+
+ name = getmem_w(reg.r[REGSP]+4);
+ edir = getmem_w(reg.r[REGSP]+8);
+ memio(nambuf, name, sizeof(nambuf), MemReadstring);
+ if(sysdbg)
+ itrace("stat(0x%lux='%s', 0x%lux)", name, nambuf, edir);
+
+ n = _stat(nambuf, buf);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ else
+ memio(buf, edir, ODIRLEN, MemWrite);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sysstat(void)
+{
+ char nambuf[1024];
+ uchar buf[STATMAX];
+ ulong edir, name;
+ int n;
+
+ name = getmem_w(reg.r[REGSP]+4);
+ edir = getmem_w(reg.r[REGSP]+8);
+ n = getmem_w(reg.r[REGSP]+12);
+ memio(nambuf, name, sizeof(nambuf), MemReadstring);
+ if(sysdbg)
+ itrace("stat(0x%lux='%s', 0x%lux, 0x%lux)", name, nambuf, edir, n);
+ if(n > sizeof buf)
+ errstr(errbuf, sizeof errbuf);
+ else{
+ n = stat(nambuf, buf, n);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ else
+ memio((char*)buf, edir, n, MemWrite);
+ }
+ reg.r[REGRET] = n;
+}
+
+void
+sys_fstat(void)
+{
+ char buf[ODIRLEN];
+ ulong edir;
+ extern int _fstat(int, char*); /* old system call */
+ int n, fd;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ edir = getmem_w(reg.r[REGSP]+8);
+ if(sysdbg)
+ itrace("fstat(%d, 0x%lux)", fd, edir);
+
+ n = _fstat(fd, buf);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ else
+ memio(buf, edir, ODIRLEN, MemWrite);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sysfstat(void)
+{
+ uchar buf[STATMAX];
+ ulong edir;
+ int n, fd;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ edir = getmem_w(reg.r[REGSP]+8);
+ n = getmem_w(reg.r[REGSP]+12);
+ if(sysdbg)
+ itrace("fstat(%d, 0x%lux, 0x%lux)", fd, edir, n);
+
+ reg.r[REGRET] = -1;
+ if(n > sizeof buf){
+ strcpy(errbuf, "stat buffer too big");
+ return;
+ }
+ n = fstat(fd, buf, n);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ else
+ memio((char*)buf, edir, n, MemWrite);
+ reg.r[REGRET] = n;
+}
+
+void
+syswrite(vlong offset)
+{
+ int fd;
+ ulong size, a;
+ char *buf;
+ int n;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ a = getmem_w(reg.r[REGSP]+8);
+ size = getmem_w(reg.r[REGSP]+12);
+
+ Bflush(bioout);
+ buf = memio(0, a, size, MemRead);
+ n = pwrite(fd, buf, size, offset);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ if(sysdbg)
+ itrace("write(%d, %lux, %d, 0xllx) = %d", fd, a, size, offset, n);
+ free(buf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sys_write(void)
+{
+ syswrite(-1LL);
+}
+
+void
+syspwrite(void)
+{
+ union {
+ vlong v;
+ ulong u[2];
+ } o;
+
+ o.u[0] = getmem_w(reg.r[REGSP]+16);
+ o.u[1] = getmem_w(reg.r[REGSP]+20);
+ syswrite(o.v);
+}
+
+void
+syspipe(void)
+{
+ int n, p[2];
+ ulong fd;
+
+ fd = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("pipe(%lux)", fd);
+
+ n = pipe(p);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ else {
+ putmem_w(fd, p[0]);
+ putmem_w(fd+4, p[1]);
+ }
+ reg.r[REGRET] = n;
+}
+
+void
+syscreate(void)
+{
+ char file[1024];
+ int n;
+ ulong mode, name, perm;
+
+ name = getmem_w(reg.r[REGSP]+4);
+ mode = getmem_w(reg.r[REGSP]+8);
+ perm = getmem_w(reg.r[REGSP]+12);
+ memio(file, name, sizeof(file), MemReadstring);
+ if(sysdbg)
+ itrace("create(0x%lux='%s', 0x%lux, 0x%lux)", name, file, mode, perm);
+
+ n = create(file, mode, perm);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sysbrk_(void)
+{
+ ulong addr, osize, nsize;
+ Segment *s;
+
+ addr = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("brk_(0x%lux)", addr);
+
+ reg.r[REGRET] = -1;
+ if(addr < memory.seg[Data].base+datasize) {
+ strcpy(errbuf, "address below segment");
+ return;
+ }
+ if(addr > memory.seg[Stack].base) {
+ strcpy(errbuf, "segment too big");
+ return;
+ }
+ s = &memory.seg[Bss];
+ if(addr > s->end) {
+ osize = ((s->end-s->base)/BY2PG)*sizeof(uchar*);
+ addr = ((addr)+(BY2PG-1))&~(BY2PG-1);
+ s->end = addr;
+ nsize = ((s->end-s->base)/BY2PG)*sizeof(uchar*);
+ s->table = erealloc(s->table, osize, nsize);
+ }
+
+ reg.r[REGRET] = 0;
+}
+
+void
+sysremove(void)
+{
+ char nambuf[1024];
+ ulong name;
+ int n;
+
+ name = getmem_w(reg.r[REGSP]+4);
+ memio(nambuf, name, sizeof(nambuf), MemReadstring);
+ if(sysdbg)
+ itrace("remove(0x%lux='%s')", name, nambuf);
+
+ n = remove(nambuf);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+ reg.r[REGRET] = n;
+}
+
+void
+sysnotify(void)
+{
+ nofunc = getmem_w(reg.r[REGSP]+4);
+ if(sysdbg)
+ itrace("notify(0x%lux)\n", nofunc);
+
+ reg.r[REGRET] = 0;
+}
+
+void
+syssegflush(void)
+{
+ int n;
+ ulong va;
+
+ va = getmem_w(reg.r[REGSP]+4);
+ n = getmem_w(reg.r[REGSP]+8);
+ if(sysdbg)
+ itrace("segflush(va=0x%lux, n=%d)\n", va, n);
+
+ reg.r[REGRET] = 0;
+}
+
+void sysfversion(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+void sysfsession(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+void sysfauth(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+void syswait(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+void syswstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sys_wstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysfwstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sys_fwstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysnoted(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void syssegattach(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void syssegdetach(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void syssegfree(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysrendezvous(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysunmount(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysfork(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysforkpgrp(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void syssegbrk(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void _sysmount(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysalarm(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysexec(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysmount(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+void sysawait(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);}
+
+void (*systab[])(void) ={
+ [SYSR1] sys1,
+ [_ERRSTR] sys_errstr,
+ [BIND] sysbind,
+ [CHDIR] syschdir,
+ [CLOSE] sysclose,
+ [DUP] sysdup,
+ [ALARM] sysalarm,
+ [EXEC] sysexec,
+ [EXITS] sysexits,
+ [_FSESSION] sysfsession,
+ [FAUTH] sysfauth,
+ [_FSTAT] sys_fstat,
+ [SEGBRK] syssegbrk,
+ [_MOUNT] _sysmount,
+ [OPEN] sysopen,
+ [_READ] sys_read,
+ [OSEEK] sysoseek,
+ [SLEEP] syssleep,
+ [_STAT] sys_stat,
+ [RFORK] sysrfork,
+ [_WRITE] sys_write,
+ [PIPE] syspipe,
+ [CREATE] syscreate,
+ [FD2PATH] sysfd2path,
+ [BRK_] sysbrk_,
+ [REMOVE] sysremove,
+ [_WSTAT] sys_wstat,
+ [_FWSTAT] sys_fwstat,
+ [NOTIFY] sysnotify,
+ [NOTED] sysnoted,
+ [SEGATTACH] syssegattach,
+ [SEGDETACH] syssegdetach,
+ [SEGFREE] syssegfree,
+ [SEGFLUSH] syssegflush,
+ [RENDEZVOUS] sysrendezvous,
+ [UNMOUNT] sysunmount,
+ [_WAIT] syswait,
+ [SEEK] sysseek,
+ [FVERSION] sysfversion,
+ [ERRSTR] syserrstr,
+ [STAT] sysstat,
+ [FSTAT] sysfstat,
+ [WSTAT] syswstat,
+ [FWSTAT] sysfwstat,
+ [MOUNT] sysmount,
+ [AWAIT] sysawait,
+ [PREAD] syspread,
+ [PWRITE] syspwrite,
+};
+
+void
+Ssyscall(ulong inst)
+{
+ int call;
+
+ USED(inst);
+ call = reg.r[REGRET];
+ if(call < 0 || call > PWRITE || systab[call] == nil) {
+ Bprint(bioout, "Bad system call\n");
+ dumpreg();
+ }
+ if(trace)
+ itrace("sysc\t%s", sysctab[call]);
+
+ (*systab[call])();
+ Bflush(bioout);
+}
diff --git a/sys/src/cmd/vi/vi.c b/sys/src/cmd/vi/vi.c
new file mode 100755
index 000000000..bc31b5bf1
--- /dev/null
+++ b/sys/src/cmd/vi/vi.c
@@ -0,0 +1,507 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern
+#include "mips.h"
+
+char *file = "v.out";
+int datasize;
+ulong textbase;
+Biobuf bp, bi;
+Fhdr fhdr;
+
+void
+main(int argc, char **argv)
+{
+ int pid;
+
+ argc--;
+ argv++;
+
+ bioout = &bp;
+ bin = &bi;
+ Binit(bioout, 1, OWRITE);
+ Binit(bin, 0, OREAD);
+
+ tlb.on = 1;
+ tlb.tlbsize = 24;
+
+ if(argc) {
+ pid = atoi(argv[0]);
+ if(pid != 0) {
+ procinit(pid);
+ cmd();
+ }
+ file = argv[0];
+ }
+ argc--;
+ argv++;
+
+ text = open(file, OREAD);
+ if(text < 0)
+ fatal(1, "open text '%s'", file);
+
+ Bprint(bioout, "vi\n");
+ inithdr(text);
+ initstk(argc, argv);
+
+ reg.fd[dreg(24)] = 0.0; /* Normally initialised by the kernel */
+ reg.ft[24] = FPd;
+ reg.fd[dreg(26)] = 0.5;
+ reg.ft[26] = FPd;
+ reg.fd[dreg(28)] = 1.0;
+ reg.ft[28] = FPd;
+ reg.fd[dreg(30)] = 2.0;
+ reg.ft[30] = FPd;
+ cmd();
+}
+
+void
+initmap()
+{
+ ulong t, d, b, bssend;
+ Segment *s;
+
+ t = (fhdr.txtaddr+fhdr.txtsz+(BY2PG-1)) & ~(BY2PG-1);
+ d = (t + fhdr.datsz + (BY2PG-1)) & ~(BY2PG-1);
+ bssend = t + fhdr.datsz + fhdr.bsssz;
+ b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
+
+ s = &memory.seg[Text];
+ s->type = Text;
+ s->base = fhdr.txtaddr - fhdr.hdrsz;
+ s->end = t;
+ s->fileoff = fhdr.txtoff - fhdr.hdrsz;
+ s->fileend = s->fileoff + fhdr.txtsz;
+ s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*));
+
+ iprof = emalloc(((s->end-s->base)/PROFGRAN)*sizeof(long));
+ textbase = s->base;
+
+ s = &memory.seg[Data];
+ s->type = Data;
+ s->base = t;
+ s->end = t+(d-t);
+ s->fileoff = fhdr.datoff;
+ s->fileend = s->fileoff + fhdr.datsz;
+ datasize = fhdr.datsz;
+ s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*));
+
+ s = &memory.seg[Bss];
+ s->type = Bss;
+ s->base = d;
+ s->end = d+(b-d);
+ s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*));
+
+ s = &memory.seg[Stack];
+ s->type = Stack;
+ s->base = STACKTOP-STACKSIZE;
+ s->end = STACKTOP;
+ s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*));
+
+ reg.pc = fhdr.entry;
+}
+
+void
+inithdr(int fd)
+{
+ Symbol s;
+
+ extern Machdata mipsmach;
+
+ seek(fd, 0, 0);
+ if (!crackhdr(fd, &fhdr))
+ fatal(0, "read text header");
+
+ if(fhdr.type != FMIPS && fhdr.type != FMIPS2BE)
+ fatal(0, "bad magic number: %d %d", fhdr.type, FMIPS);
+
+ if (syminit(fd, &fhdr) < 0)
+ fatal(0, "%r\n");
+
+ symmap = loadmap(symmap, fd, &fhdr);
+ if (mach->sbreg && lookup(0, mach->sbreg, &s))
+ mach->sb = s.value;
+ machdata = &mipsmach;
+}
+
+ulong
+greg(int f, ulong off)
+{
+ int n;
+ ulong l;
+ uchar wd[BY2WD];
+
+ seek(f, off, 0);
+ n = read(f, wd, BY2WD);
+ if(n != BY2WD)
+ fatal(1, "read register");
+
+ l = wd[0]<<24;
+ l |= wd[1]<<16;
+ l |= wd[2]<<8;
+ l |= wd[3];
+ return l;
+}
+
+ulong
+roff[] = {
+ REGOFF(r1), REGOFF(r2), REGOFF(r3),
+ REGOFF(r4), REGOFF(r5), REGOFF(r6),
+ REGOFF(r7), REGOFF(r8), REGOFF(r9),
+ REGOFF(r10), REGOFF(r11), REGOFF(r12),
+ REGOFF(r13), REGOFF(r14), REGOFF(r15),
+ REGOFF(r16), REGOFF(r17), REGOFF(r18),
+ REGOFF(r19), REGOFF(r20), REGOFF(r21),
+ REGOFF(r22), REGOFF(r23), REGOFF(r24),
+ REGOFF(r25), REGOFF(r26), REGOFF(r27),
+ REGOFF(r28)
+};
+
+void
+seginit(int fd, Segment *s, int idx, ulong vastart, ulong vaend)
+{
+ int n;
+
+ while(vastart < vaend) {
+ seek(fd, vastart, 0);
+ s->table[idx] = emalloc(BY2PG);
+ n = read(fd, s->table[idx], BY2PG);
+ if(n != BY2PG)
+ fatal(1, "data read");
+ vastart += BY2PG;
+ idx++;
+ }
+}
+
+void
+procinit(int pid)
+{
+ char *p;
+ Segment *s;
+ int n, m, sg, i;
+ ulong vastart, vaend;
+ char mfile[128], tfile[128], sfile[1024];
+
+ sprint(mfile, "/proc/%d/mem", pid);
+ sprint(tfile, "/proc/%d/text", pid);
+ sprint(sfile, "/proc/%d/segment", pid);
+
+ text = open(tfile, OREAD);
+ if(text < 0)
+ fatal(1, "open text %s", tfile);
+ inithdr(text);
+
+ sg = open(sfile, OREAD);
+ if(sg < 0)
+ fatal(1, "open text %s", sfile);
+
+ n = read(sg, sfile, sizeof(sfile));
+ if(n >= sizeof(sfile))
+ fatal(0, "segment file buffer too small");
+ close(sg);
+
+ m = open(mfile, OREAD);
+ if(m < 0)
+ fatal(1, "open %s", mfile);
+
+ initmap();
+ p = strstr(sfile, "Data");
+ if(p == 0)
+ fatal(0, "no data");
+
+ vastart = strtoul(p+9, 0, 16);
+ vaend = strtoul(p+18, 0, 16);
+ s = &memory.seg[Data];
+ if(s->base != vastart || s->end != vaend) {
+ s->base = vastart;
+ s->end = vaend;
+ free(s->table);
+ s->table = malloc(((s->end-s->base)/BY2PG)*sizeof(uchar*));
+ }
+ seginit(m, s, 0, vastart, vaend);
+
+ p = strstr(sfile, "Bss");
+ if(p == 0)
+ fatal(0, "no bss");
+
+ vastart = strtoul(p+9, 0, 16);
+ vaend = strtoul(p+18, 0, 16);
+ s = &memory.seg[Bss];
+ if(s->base != vastart || s->end != vaend) {
+ s->base = vastart;
+ s->end = vaend;
+ free(s->table);
+ s->table = malloc(((s->end-s->base)/BY2PG)*sizeof(uchar*));
+ }
+ seginit(m, s, 0, vastart, vaend);
+
+ reg.pc = greg(m, REGOFF(pc));
+ reg.r[29] = greg(m, REGOFF(sp));
+ reg.r[30] = greg(m, REGOFF(r30));
+ reg.r[31] = greg(m, REGOFF(r31));
+
+ reg.mhi = greg(m, REGOFF(hi));
+ reg.mlo = greg(m, REGOFF(lo));
+
+ for(i = 1; i < 29; i++)
+ reg.r[i] = greg(m, roff[i-1]);
+
+ s = &memory.seg[Stack];
+ vastart = reg.r[29] & ~(BY2PG-1);
+ seginit(m, s, (vastart-s->base)/BY2PG, vastart, STACKTOP);
+ close(m);
+ Bprint(bioout, "vi\n");
+}
+
+void
+reset(void)
+{
+ int i, l, m;
+ Segment *s;
+ Breakpoint *b;
+
+ memset(&reg, 0, sizeof(Registers));
+ reg.fd[dreg(24)] = 0.0; /* Normally initialised by the kernel */
+ reg.ft[24] = FPd;
+ reg.fd[dreg(26)] = 0.5;
+ reg.ft[26] = FPd;
+ reg.fd[dreg(28)] = 1.0;
+ reg.ft[28] = FPd;
+ reg.fd[dreg(30)] = 2.0;
+ reg.ft[30] = FPd;
+
+ for(i = 0; i > Nseg; i++) {
+ s = &memory.seg[i];
+ l = ((s->end-s->base)/BY2PG)*sizeof(uchar*);
+ for(m = 0; m < l; m++)
+ if(s->table[m])
+ free(s->table[m]);
+ free(s->table);
+ }
+ free(iprof);
+ memset(&memory, 0, sizeof(memory));
+
+ for(b = bplist; b; b = b->next)
+ b->done = b->count;
+}
+
+void
+initstk(int argc, char *argv[])
+{
+ ulong size;
+ ulong sp, ap;
+ int i;
+ char *p;
+
+ initmap();
+ sp = STACKTOP - 4;
+
+ /* Build exec stack */
+ size = strlen(file)+1+BY2WD+BY2WD+BY2WD;
+ for(i = 0; i < argc; i++)
+ size += strlen(argv[i])+BY2WD+1;
+
+ sp -= size;
+ sp &= ~3;
+ reg.r[29] = sp;
+ reg.r[1] = STACKTOP-4; /* Plan 9 profiling clock */
+
+ /* Push argc */
+ putmem_w(sp, argc+1);
+ sp += BY2WD;
+
+ /* Compute sizeof(argv) and push argv[0] */
+ ap = sp+((argc+1)*BY2WD)+BY2WD;
+ putmem_w(sp, ap);
+ sp += BY2WD;
+
+ /* Build argv[0] string into stack */
+ for(p = file; *p; p++)
+ putmem_b(ap++, *p);
+
+ putmem_b(ap++, '\0');
+
+ /* Loop through pushing the arguments */
+ for(i = 0; i < argc; i++) {
+ putmem_w(sp, ap);
+ sp += BY2WD;
+ for(p = argv[i]; *p; p++)
+ putmem_b(ap++, *p);
+ putmem_b(ap++, '\0');
+ }
+ /* Null terminate argv */
+ putmem_w(sp, 0);
+
+}
+
+void
+fatal(int syserr, char *fmt, ...)
+{
+ char buf[ERRMAX], *s;
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ s = "vi: %s\n";
+ if(syserr)
+ s = "vi: %s: %r\n";
+ fprint(2, s, buf);
+ exits(buf);
+}
+
+void
+itrace(char *fmt, ...)
+{
+ char buf[128];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(bioout, "%8lux %.8lux %s\n", reg.pc, reg.ir, buf);
+}
+
+void
+dumpreg(void)
+{
+ int i;
+
+ Bprint(bioout, "PC #%-8lux SP #%-8lux HI #%-8lux LO #%-8lux\n",
+ reg.pc, reg.r[29], reg.mhi, reg.mlo);
+
+ for(i = 0; i < 32; i++) {
+ if((i%4) == 0 && i != 0)
+ Bprint(bioout, "\n");
+ Bprint(bioout, "R%-2d #%-8lux ", i, reg.r[i]);
+ }
+ Bprint(bioout, "\n");
+}
+
+void
+dumpfreg(void)
+{
+ int i;
+ char buf[64];
+
+ i = 0;
+ while(i < 32) {
+ ieeesftos(buf, sizeof(buf), reg.di[i]);
+ Bprint(bioout, "F%-2d %s\t", i, buf);
+ i++;
+
+ ieeesftos(buf, sizeof(buf), reg.di[i]);
+ Bprint(bioout, "\t\t\tF%-2d %s\n", i, buf);
+ i++;
+ }
+}
+
+void
+dumpdreg(void)
+{
+ int i;
+ char buf[64];
+
+ i = 0;
+ while(i < 32) {
+ if(reg.ft[i] == FPd)
+ ieeedftos(buf, sizeof(buf), reg.di[i] ,reg.di[i+1]);
+ else
+ ieeedftos(buf, sizeof(buf), reg.di[i+1] ,reg.di[i]);
+ Bprint(bioout, "F%-2d %s\t\t\t", i, buf);
+ i += 2;
+
+ if(reg.ft[i] == FPd)
+ ieeedftos(buf, sizeof(buf), reg.di[i] ,reg.di[i+1]);
+ else
+ ieeedftos(buf, sizeof(buf), reg.di[i+1] ,reg.di[i]);
+ Bprint(bioout, "F%-2d %s\n", i, buf);
+ i += 2;
+ }
+}
+
+void *
+emalloc(ulong size)
+{
+ void *a;
+
+ a = malloc(size);
+ if(a == 0)
+ fatal(0, "no memory");
+
+ memset(a, 0, size);
+ return a;
+}
+
+void *
+erealloc(void *a, ulong oldsize, ulong size)
+{
+ void *n;
+
+ n = malloc(size);
+ if(n == 0)
+ fatal(0, "no memory");
+ memset(n, 0, size);
+ if(size > oldsize)
+ size = oldsize;
+ memmove(n, a, size);
+ return n;
+}
+
+Mulu
+mulu(ulong u1, ulong u2)
+{
+ ulong lo1, lo2, hi1, hi2, lo, hi, t1, t2, t;
+
+ lo1 = u1 & 0xffff;
+ lo2 = u2 & 0xffff;
+ hi1 = u1 >> 16;
+ hi2 = u2 >> 16;
+
+ lo = lo1 * lo2;
+ t1 = lo1 * hi2;
+ t2 = lo2 * hi1;
+ hi = hi1 * hi2;
+ t = lo;
+ lo += t1 << 16;
+ if(lo < t)
+ hi++;
+ t = lo;
+ lo += t2 << 16;
+ if(lo < t)
+ hi++;
+ hi += (t1 >> 16) + (t2 >> 16);
+ return (Mulu){lo, hi};
+}
+
+Mul
+mul(long l1, long l2)
+{
+ Mulu m;
+ ulong t, lo, hi;
+ int sign;
+
+ sign = 0;
+ if(l1 < 0){
+ sign ^= 1;
+ l1 = -l1;
+ }
+ if(l2 < 0){
+ sign ^= 1;
+ l2 = -l2;
+ }
+ m = mulu(l1, l2);
+ lo = m.lo;
+ hi = m.hi;
+ if(sign){
+ t = lo = ~lo;
+ hi = ~hi;
+ lo++;
+ if(lo < t)
+ hi++;
+ }
+ return (Mul){lo, hi};
+}
+