summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ki
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/ki
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ki')
-rwxr-xr-xsys/src/cmd/ki/bpt.c129
-rwxr-xr-xsys/src/cmd/ki/cmd.c632
-rwxr-xr-xsys/src/cmd/ki/float.c445
-rwxr-xr-xsys/src/cmd/ki/icache.c18
-rwxr-xr-xsys/src/cmd/ki/ki.c484
-rwxr-xr-xsys/src/cmd/ki/mem.c240
-rwxr-xr-xsys/src/cmd/ki/mkfile27
-rwxr-xr-xsys/src/cmd/ki/run.c1411
-rwxr-xr-xsys/src/cmd/ki/sparc.h236
-rwxr-xr-xsys/src/cmd/ki/stats.c214
-rwxr-xr-xsys/src/cmd/ki/symbols.c97
-rwxr-xr-xsys/src/cmd/ki/syscall.c729
12 files changed, 4662 insertions, 0 deletions
diff --git a/sys/src/cmd/ki/bpt.c b/sys/src/cmd/ki/bpt.c
new file mode 100755
index 000000000..6647034a5
--- /dev/null
+++ b/sys/src/cmd/ki/bpt.c
@@ -0,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.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, "%s", 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, "%s", 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, "%s", 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, "%s", buf);
+ break;
+
+ case Equal:
+ Bprint(bioout, "0x%lux,%d:be at ", b->addr, b->count);
+ symoff(buf, sizeof(buf), b->addr, CDATA);
+ Bprint(bioout, "%s", 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/ki/cmd.c b/sys/src/cmd/ki/cmd.c
new file mode 100755
index 000000000..095ae0271
--- /dev/null
+++ b/sys/src/cmd/ki/cmd.c
@@ -0,0 +1,632 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.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)
+{
+ cp = nextc(cp);
+ switch(*cp) {
+ default:
+ Bprint(bioout, "?\n");
+ break;
+
+ case 'c':
+ case 'C':
+ stktrace(*cp);
+ break;
+
+ case 'b':
+ dobplist();
+ break;
+
+ case 'r':
+ dumpreg();
+ break;
+
+ case 'R':
+ dumpreg();
+ /* fall through */
+
+ case 'f':
+ dumpfreg();
+ break;
+
+ case 'F':
+ dumpdreg();
+ break;
+
+ case 'q':
+ exits(0);
+ break;
+
+ case 'Q':
+ isum();
+ segsum();
+ break;
+
+ case 't':
+ cp++;
+ switch(*cp) {
+ default:
+ Bprint(bioout, ":t[0sic]\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;
+ }
+ break;
+
+ case 'i':
+ cp++;
+ switch(*cp) {
+ default:
+ Bprint(bioout, "$i[isa]\n");
+ break;
+ case 'i':
+ isum();
+ break;
+ case 's':
+ segsum();
+ break;
+ case 'a':
+ isum();
+ 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, "%-3d ", (int)(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);
+ Bprint(bioout, "%s", 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':
+ case 'i':
+ inc = machdata->das(symmap, dot, fmt, str, sizeof(str));
+ if (inc < 0) {
+ Bprint(bioout, "ki: %r\n");
+ return 0;
+ }
+ c = Bprint(bioout, "\t%s", 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("ki\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[1] = dot;
+ return;
+ }
+ if(strcmp(cp, "y") == 0) {
+ reg.Y = dot;
+ return;
+ }
+ if(strcmp(cp, "psr") == 0) {
+ reg.psr = 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/ki/float.c b/sys/src/cmd/ki/float.c
new file mode 100755
index 000000000..a73472901
--- /dev/null
+++ b/sys/src/cmd/ki/float.c
@@ -0,0 +1,445 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.h"
+
+void
+ldf(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ldf\tf%d,0x%lux(r%d) ea=%lux",rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ldf\tf%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.di[rd] = getmem_w(ea);
+}
+
+void
+lddf(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("lddf\tf%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("lddf\tf%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ if(ea&7) {
+ Bprint(bioout, "mem_address_not_aligned [load addr %.8lux]\n", ea);
+ longjmp(errjmp, 0);
+ }
+ if(rd&1)
+ undef(ir);
+
+ reg.di[rd] = getmem_w(ea);
+ reg.di[rd+1] = getmem_w(ea+4);
+}
+
+void
+stf(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("stf\tf%d,0x%lux(r%d) %lux=%g",
+ rd, ea, rs1, ea+reg.r[rs1], reg.fl[rd]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("stf\tf%d,[r%d+r%d] %lux=%lux",
+ rd, rs1, rs2, ea, reg.r[rd]);
+ }
+
+ putmem_w(ea, reg.di[rd]);
+}
+
+void
+stdf(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("stdf\tf%d,0x%lux(r%d) %lux=%g",
+ rd, ea, rs1, ea+reg.r[rs1], reg.fl[rd]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("stdf\tf%d,[r%d+r%d] %lux=%lux",
+ rd, rs1, rs2, ea, reg.r[rd]);
+ }
+
+ if(ea&7) {
+ Bprint(bioout, "mem_address_not_aligned [store addr %.8lux]\n", ea);
+ longjmp(errjmp, 0);
+ }
+ if(rd&1)
+ undef(ir);
+
+ putmem_w(ea, reg.di[rd]);
+ putmem_w(ea+4, reg.di[rd+1]);
+}
+
+void
+fcmp(ulong ir)
+{
+ int fc, rd, rs1, rs2;
+
+ getrop23(ir);
+ USED(rd);
+ SET(fc);
+ switch((ir>>5)&0x1FF) {
+ default:
+ undef(ir);
+ case 0x51: /* fcmps */
+ if(trace)
+ itrace("fcmps\tf%d,f%d", rs1, rs2);
+ if(isNaN(reg.fl[rs1]) || isNaN(reg.fl[rs2])) {
+ fc = 3;
+ break;
+ }
+ if(reg.fl[rs1] == reg.fl[rs2]) {
+ fc = 0;
+ break;
+ }
+ if(reg.fl[rs1] < reg.fl[rs2]) {
+ fc = 1;
+ break;
+ }
+ if(reg.fl[rs1] > reg.fl[rs2]) {
+ fc = 2;
+ break;
+ }
+ print("ki: fcmp error\n");
+ break;
+ case 0x52:
+ if(trace)
+ itrace("fcmpd\tf%d,f%d", rs1, rs2);
+ rs1 >>= 1;
+ rs2 >>= 1;
+ if(isNaN(reg.fd[rs1]) || isNaN(reg.fd[rs2])) {
+ fc = 3;
+ break;
+ }
+ if(reg.fd[rs1] == reg.fd[rs2]) {
+ fc = 0;
+ break;
+ }
+ if(reg.fd[rs1] < reg.fd[rs2]) {
+ fc = 1;
+ break;
+ }
+ if(reg.fd[rs1] > reg.fd[rs2]) {
+ fc = 2;
+ break;
+ }
+ print("ki: fcmp error\n");
+ break;
+ case 0x55: /* fcmpes */
+ if(trace)
+ itrace("fcmpes\tf%d,f%d", rs1, rs2);
+ rs1 >>= 1;
+ rs2 >>= 2;
+ if(isNaN(reg.fl[rs1]) || isNaN(reg.fl[rs2])) {
+ Bprint(bioout, "invalid_fp_register\n");
+ longjmp(errjmp, 0);
+ }
+ if(reg.fl[rs1] == reg.fl[rs2]) {
+ fc = 0;
+ break;
+ }
+ if(reg.fl[rs1] < reg.fl[rs2]) {
+ fc = 1;
+ break;
+ }
+ if(reg.fl[rs1] > reg.fl[rs2]) {
+ fc = 2;
+ break;
+ }
+ print("ki: fcmp error\n");
+ break;
+ case 0x56:
+ if(trace)
+ itrace("fcmped\tf%d,f%d", rs1, rs2);
+ if(isNaN(reg.fd[rs1]) || isNaN(reg.fd[rs2])) {
+ Bprint(bioout, "invalid_fp_register\n");
+ longjmp(errjmp, 0);
+ }
+ if(reg.fd[rs1] == reg.fd[rs2]) {
+ fc = 0;
+ break;
+ }
+ if(reg.fd[rs1] < reg.fd[rs2]) {
+ fc = 1;
+ break;
+ }
+ if(reg.fd[rs1] > reg.fd[rs2]) {
+ fc = 2;
+ break;
+ }
+ print("ki: fcmp error\n");
+ break;
+
+ }
+ reg.fpsr = (reg.fpsr&~(0x3<<10)) | (fc<<10);
+}
+
+void
+fbcc(ulong ir)
+{
+ char *op;
+ ulong npc;
+ int takeit, fc, ba, anul;
+
+ fc = (reg.fpsr>>10)&3;
+ ba = 0;
+ SET(op, takeit);
+ switch((ir>>25)&0x0F) {
+ case 0:
+ op = "fbn";
+ takeit = 0;
+ break;
+ case 1:
+ op = "fbne";
+ takeit = fc == FP_L || fc == FP_G || fc == FP_U;
+ break;
+ case 2:
+ op = "fblg";
+ takeit = fc == FP_L || fc == FP_G;
+ break;
+ case 3:
+ op = "fbul";
+ takeit = fc == FP_L || fc == FP_U;
+ break;
+ case 4:
+ op = "fbl";
+ takeit = fc == FP_L;
+ break;
+ case 5:
+ op = "fbug";
+ takeit = fc == FP_U || fc == FP_G;
+ break;
+ case 6:
+ op = "fbg";
+ takeit = fc == FP_G;
+ break;
+ case 7:
+ op = "fbu";
+ takeit = fc == FP_U;
+ break;
+ case 8:
+ op = "fba";
+ ba = 1;
+ takeit = 1;
+ break;
+ case 9:
+ op = "fbe";
+ takeit = fc == FP_E;
+ break;
+ case 10:
+ op = "fbue";
+ takeit = fc == FP_E || fc == FP_U;
+ break;
+ case 11:
+ op = "fbge";
+ takeit = fc == FP_E || fc == FP_G;
+ break;
+ case 12:
+ op = "fbuge";
+ takeit = fc == FP_E || fc == FP_G || fc == FP_U;
+ break;
+ case 13:
+ op = "fble";
+ takeit = fc == FP_E || fc == FP_L;
+ break;
+ case 14:
+ op = "fbule";
+ takeit = fc == FP_E || fc == FP_L || fc == FP_U;
+ break;
+ case 15:
+ op = "fbo";
+ takeit = fc == FP_E || fc == FP_L || fc == FP_G;
+ break;
+ }
+
+ npc = ir & 0x3FFFFF;
+ if(npc & (1<<21))
+ npc |= ~((1<<22)-1);
+ npc = (npc<<2) + reg.pc;
+
+ anul = ir&ANUL;
+ if(trace) {
+ if(anul)
+ itrace("%s,a\t%lux", op, npc);
+ else
+ itrace("%s\t%lux", op, npc);
+ }
+
+ if(takeit == 0) {
+ reg.pc += 4;
+ if(anul == 0) {
+ reg.ir = ifetch(reg.pc);
+ delay(reg.pc+4);
+ }
+ else
+ anulled++;
+ return;
+ }
+
+ ci->taken++;
+ if(ba && anul) {
+ reg.pc = npc-4;
+ anulled++;
+ return;
+ }
+ reg.ir = ifetch(reg.pc+4);
+ delay(npc);
+ reg.pc = npc-4;
+}
+
+void
+farith(ulong ir)
+{
+ char *op;
+ long v;
+ int rd, rs1, rs2, fmt;
+
+ fmt = 0;
+ getrop23(ir);
+ switch((ir>>5)&0x1FF) {
+ default:
+ undef(ir);
+ case 0x41:
+ reg.fl[rd] = reg.fl[rs1] + reg.fl[rs2];
+ op = "fadds";
+ break;
+ case 0x42:
+ reg.fd[rd>>1] = reg.fd[rs1>>1] + reg.fd[rs2>>1];
+ op = "faddd";
+ break;
+ case 0x45:
+ reg.fl[rd] = reg.fl[rs1] - reg.fl[rs2];
+ op = "fsubs";
+ break;
+ case 0x46:
+ reg.fd[rd>>1] = reg.fd[rs1>>1] - reg.fd[rs2>>1];
+ op = "fsubd";
+ break;
+ case 0x4d:
+ if(reg.fl[rs2] == 0.0) {
+ Bprint(bioout, "fp_exception DZ\n");
+ longjmp(errjmp, 0);
+ }
+ reg.fl[rd] = reg.fl[rs1] / reg.fl[rs2];
+ op = "fdivs";
+ break;
+ case 0x4e:
+ if(reg.fd[rs2>>1] == 0.0) {
+ Bprint(bioout, "fp_exception DZ\n");
+ longjmp(errjmp, 0);
+ }
+ reg.fd[rd>>1] = reg.fd[rs1>>1] / reg.fd[rs2>>1];
+ op = "fdivd";
+ break;
+ case 0x49:
+ reg.fl[rd] = reg.fl[rs1] * reg.fl[rs2];
+ op = "fmuls";
+ break;
+ case 0x4a:
+ reg.fd[rd>>1] = reg.fd[rs1>>1] * reg.fd[rs2>>1];
+ op = "fmuld";
+ break;
+ case 0xc4:
+ reg.fl[rd] = (long)reg.di[rs2];
+ fmt = 1;
+ op = "fitos";
+ break;
+ case 0xc8:
+ reg.fd[rd>>1] = (long)reg.di[rs2];
+ fmt = 1;
+ op = "fitod";
+ break;
+ case 0xd1:
+ v = reg.fl[rs2];
+ reg.di[rd] = v;
+ fmt = 1;
+ op = "fstoi";
+ break;
+ case 0xd2:
+ v = reg.fd[rs2>>1];
+ reg.di[rd] = v;
+ fmt = 1;
+ op = "fdtoi";
+ break;
+ case 0x01:
+ reg.di[rd] = reg.di[rs2];
+ fmt = 1;
+ op = "fmovs";
+ break;
+ case 0x05:
+ reg.fl[rd] = -reg.fl[rs2];
+ fmt = 1;
+ op = "fnegs";
+ break;
+ case 0x09:
+ reg.fl[rd] = fabs(reg.fl[rs2]);
+ fmt = 1;
+ op = "fabss";
+ break;
+ case 0xc9:
+ reg.fd[rd>>1] = reg.fl[rs2];
+ fmt = 1;
+ op = "fstod";
+ break;
+ case 0xc6:
+ reg.fl[rd] = reg.fd[rs2>>1];
+ fmt = 1;
+ op = "fdtos";
+ break;
+ }
+
+ if(trace) {
+ switch(fmt) {
+ case 0:
+ itrace("%s\tf%d,f%d,f%d", op, rs1, rs2, rd);
+ break;
+ case 1:
+ itrace("%s\tf%d,f%d", op, rs2, rd);
+ break;
+ }
+ }
+}
diff --git a/sys/src/cmd/ki/icache.c b/sys/src/cmd/ki/icache.c
new file mode 100755
index 000000000..0e1ecb45c
--- /dev/null
+++ b/sys/src/cmd/ki/icache.c
@@ -0,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.h"
+
+void
+icacheinit(void)
+{
+}
+
+void
+updateicache(ulong addr)
+{
+ USED(addr);
+}
+
diff --git a/sys/src/cmd/ki/ki.c b/sys/src/cmd/ki/ki.c
new file mode 100755
index 000000000..6a07e7be5
--- /dev/null
+++ b/sys/src/cmd/ki/ki.c
@@ -0,0 +1,484 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern
+#include "sparc.h"
+
+char *file = "k.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);
+
+ 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, "ki\n");
+ inithdr(text);
+ initstk(argc, argv);
+
+ reg.fd[13] = 0.5; /* Normally initialised by the kernel */
+ reg.fd[12] = 0.0;
+ reg.fd[14] = 1.0;
+ reg.fd[15] = 2.0;
+ cmd();
+}
+
+void
+initmap(void)
+{
+
+ 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 sparcmach;
+
+ seek(fd, 0, 0);
+ if (!crackhdr(fd, &fhdr))
+ fatal(0, "read text header");
+
+ if(fhdr.type != FSPARC)
+ fatal(0, "bad magic number");
+
+ 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 = &sparcmach;
+ asstype = ASUNSPARC;
+}
+
+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[1] = greg(m, REGOFF(sp));
+ reg.r[30] = greg(m, REGOFF(r30));
+ reg.r[31] = greg(m, REGOFF(r31));
+
+ for(i = 1; i < 29; i++)
+ reg.r[i] = greg(m, roff[i-1]);
+
+ s = &memory.seg[Stack];
+ vastart = reg.r[1] & ~(BY2PG-1);
+ seginit(m, s, (vastart-s->base)/BY2PG, vastart, STACKTOP);
+ close(m);
+ Bprint(bioout, "ki\n");
+}
+
+void
+reset(void)
+{
+ int i, l, m;
+ Segment *s;
+ Breakpoint *b;
+
+ memset(&reg, 0, sizeof(Registers));
+ reg.fd[13] = 0.5; /* Normally initialised by the kernel */
+ reg.fd[12] = 0.0;
+ reg.fd[14] = 1.0;
+ reg.fd[15] = 2.0;
+ 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, sp, ap;
+ int i;
+ char *p;
+
+ initmap();
+ sp = STACKTOP - 4;
+
+ /* Build exec stack */
+ size = strlen(file)+1+BY2WD+BY2WD+(BY2WD*2);
+ for(i = 0; i < argc; i++)
+ size += strlen(argv[i])+BY2WD+1;
+
+ sp -= size;
+ sp &= ~7;
+ reg.r[1] = sp;
+ reg.r[7] = 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 = "ki: %s\n";
+ if(syserr)
+ s = "ki: %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 Y #%-8lux PSR #%-8lux\n",
+ reg.pc, reg.r[1], reg.Y, reg.psr);
+
+ 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, "\tF%-2d %s\n", i, buf);
+ i++;
+ }
+}
+
+void
+dumpdreg(void)
+{
+ int i;
+ char buf[64];
+
+ i = 0;
+ while(i < 32) {
+ ieeedftos(buf, sizeof(buf), reg.di[i] ,reg.di[i+1]);
+ Bprint(bioout, "F%-2d %s\t", i, buf);
+ i += 2;
+ ieeedftos(buf, sizeof(buf), reg.di[i] ,reg.di[i+1]);
+ Bprint(bioout, "\tF%-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};
+}
diff --git a/sys/src/cmd/ki/mem.c b/sys/src/cmd/ki/mem.c
new file mode 100755
index 000000000..0ab7d580b
--- /dev/null
+++ b/sys/src/cmd/ki/mem.c
@@ -0,0 +1,240 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.h"
+
+extern ulong textbase;
+
+ulong
+ifetch(ulong addr)
+{
+ uchar *va;
+
+ if(addr&3) {
+ Bprint(bioout, "instruction_address_not_aligned [addr %.8lux]\n", addr);
+ longjmp(errjmp, 0);
+ }
+
+ if(icache.on)
+ updateicache(addr);
+
+ va = vaddr(addr);
+ iprof[(addr-textbase)/PROFGRAN]++;
+
+ 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, "mem_address_not_aligned [load addr %.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, "mem_address_not_aligned [load addr %.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, "mem_address_not_aligned [store addr %.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, "mem_address_not_aligned [store addr %.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 *
+vaddr(ulong addr)
+{
+ Segment *s, *es;
+ int off, foff, l, n;
+ uchar **p, *a;
+
+ 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;
+ }
+ }
+ }
+ Bprint(bioout, "data_access_MMU_miss [addr 0x%.8lux]\n", addr);
+ longjmp(errjmp, 0);
+ return 0; /*to stop compiler whining*/
+}
diff --git a/sys/src/cmd/ki/mkfile b/sys/src/cmd/ki/mkfile
new file mode 100755
index 000000000..b0434f635
--- /dev/null
+++ b/sys/src/cmd/ki/mkfile
@@ -0,0 +1,27 @@
+</$objtype/mkfile
+
+TARG=ki
+OFILES= ki.$O\
+ run.$O\
+ mem.$O\
+ syscall.$O\
+ stats.$O\
+ icache.$O\
+ symbols.$O\
+ cmd.$O\
+ bpt.$O\
+ float.$O\
+
+HFILES=sparc.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/ki/run.c b/sys/src/cmd/ki/run.c
new file mode 100755
index 000000000..269eaa44c
--- /dev/null
+++ b/sys/src/cmd/ki/run.c
@@ -0,0 +1,1411 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.h"
+
+void add(ulong);
+void and(ulong);
+void or(ulong);
+void xor(ulong);
+void sub(ulong);
+void andn(ulong);
+void xnor(ulong);
+void subcc(ulong);
+void sll(ulong);
+void srl(ulong);
+void sra(ulong);
+void jmpl(ulong);
+void andcc(ulong);
+void xorcc(ulong);
+void andncc(ulong);
+void wry(ulong);
+void rdy(ulong);
+void mulscc(ulong);
+void fcmp(ulong);
+void farith(ulong);
+void addcc(ulong);
+void addx(ulong);
+void addxcc(ulong);
+void orcc(ulong);
+void orncc(ulong);
+void xnorcc(ulong);
+void orn(ulong);
+
+Inst op2[] = {
+ { add, "add", Iarith },
+ { and, "and", Iarith },
+ { or, "or", Iarith },
+ { xor, "xor", Iarith },
+ { sub, "sub", Iarith },
+ { andn, "andn", Iarith },
+ { orn, "orn", Inop },
+ { xnor, "xnor", Iarith },
+ { addx, "addx", Iarith },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { addcc, "addcc", Iarith },
+ { andcc, "andcc", Iarith },
+ { orcc, "orcc", Iarith },
+ { xorcc, "xorcc", Iarith },
+ { subcc, "subcc", Iarith },
+ { andncc, "andncc",Iarith },
+ { orncc, "orncc", Iarith },
+ { xnorcc, "xnorcc",Iarith },
+ { addxcc, "addxcc",Iarith },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { mulscc, "mulscc", Iarith },
+ { sll, "sll", Iarith },
+ { srl, "srl", Iarith },
+ { sra, "sra", Iarith },
+ { rdy, "rdy", Ireg },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { wry, "wry", Ireg },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { farith, "farith", Ifloat },
+ { fcmp, "fcmp", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { jmpl, "jmpl", Ibranch },
+ { undef, "" },
+ { ta, "ta", Isyscall },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { 0 }
+};
+
+void st(ulong);
+void stb(ulong);
+void sth(ulong);
+void ld(ulong);
+void ldub(ulong);
+void ldsb(ulong);
+void lduh(ulong);
+void stf(ulong);
+void ldf(ulong);
+void ldsh(ulong);
+void std(ulong);
+void ldd(ulong);
+void ldstub(ulong);
+void swap(ulong);
+void lddf(ulong);
+void stdf(ulong);
+
+Inst op3[] = {
+ { ld, "ld", Iload },
+ { ldub, "ldub", Iload },
+ { lduh, "lduh", Iload },
+ { ldd, "ldd", Iload },
+ { st, "st", Istore },
+ { stb, "stb", Istore },
+ { sth, "sth", Istore },
+ { std, "std", Istore },
+ { undef, "" },
+ { ldsb, "ldsb", Iload },
+ { ldsh, "ldsh", Iload },
+ { undef, "" },
+ { undef, "" },
+ { ldstub, "ldstub", Iload },
+ { undef, "" },
+ { swap, "swap", Iload },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { ldf, "ldf", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { lddf, "lddf", Ifloat },
+ { stf, "stf", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { stdf, "stdf", Ifloat },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { undef, "" },
+ { 0 }
+};
+
+void sethi(ulong);
+void bicc(ulong);
+void fbcc(ulong);
+void call(ulong);
+
+Inst op0[] = {
+ { undef, "" },
+ { undef, "" },
+ { bicc, "bicc", Ibranch },
+ { undef, "" },
+ { sethi, "sethi",Iarith },
+ { undef, "" },
+ { fbcc, "fbcc", Ibranch },
+ { undef, "" },
+ /* This is a fake and connot be reached by op0 decode */
+ { call, "call", Ibranch },
+ { 0 }
+};
+
+void call(ulong);
+
+void
+run(void)
+{
+ do {
+ reg.r[0] = 0;
+ reg.ir = ifetch(reg.pc);
+ switch(reg.ir>>30) {
+ case 0:
+ ci = &op0[(reg.ir>>22)&0x07];
+ ci->count++;
+ (*ci->func)(reg.ir);
+ break;
+ case 1:
+ ci = &op0[8];
+ ci->count++;
+ call(reg.ir);
+ break;
+ case 2:
+ ci = &op2[(reg.ir>>19)&0x3f];
+ ci->count++;
+ (*ci->func)(reg.ir);
+ break;
+ case 3:
+ ci = &op3[(reg.ir>>19)&0x3f];
+ ci->count++;
+ (*ci->func)(reg.ir);
+ break;
+ }
+ reg.pc += 4;
+ if(bplist)
+ brkchk(reg.pc, Instruction);
+ }while(--count);
+}
+
+void
+ilock(int rd)
+{
+ ulong ir;
+
+ ir = getmem_4(reg.pc+4);
+ switch(ir>>30) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ if(((ir>>20)&0x1f) == 0x1a) /* floating point */
+ break;
+ case 3:
+ if(rd == ((ir>>14)&0x1f)) {
+ loadlock++;
+ break;
+ }
+ if(ir&IMMBIT)
+ break;
+ if(rd == (ir&0x1f))
+ loadlock++;
+ break;
+ }
+}
+
+void
+delay(ulong npc)
+{
+ ulong opc;
+
+ reg.r[0] = 0;
+ if(reg.ir != NOP)
+ ci->useddelay++;
+ switch(reg.ir>>30) {
+ case 0:
+ ci = &op0[(reg.ir>>22)&0x07];
+ ci->count++;
+ (*ci->func)(reg.ir);
+ break;
+ case 1:
+ ci = &op0[8];
+ ci->count++;
+ call(reg.ir);
+ break;
+ case 2:
+ ci = &op2[(reg.ir>>19)&0x3f];
+ ci->count++;
+ opc = reg.pc;
+ reg.pc = npc-4;
+ (*ci->func)(reg.ir);
+ reg.pc = opc;
+ break;
+ case 3:
+ ci = &op3[(reg.ir>>19)&0x3f];
+ ci->count++;
+ opc = reg.pc;
+ reg.pc = npc-4;
+ (*ci->func)(reg.ir);
+ reg.pc = opc;
+ break;
+ }
+}
+
+void
+undef(ulong ir)
+{
+/* Bprint(bioout, "op=%d op2=%d op3=%d\n", ir>>30, (ir>>21)&0x7, (ir>>19)&0x3f); */
+ Bprint(bioout, "illegal_instruction IR #%.8lux\n", ir);
+ longjmp(errjmp, 0);
+}
+
+void
+sub(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("sub\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("sub\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] - v;
+}
+
+void
+sll(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("sll\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2]&0x1F;
+ if(trace)
+ itrace("sll\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] << v;
+}
+
+void
+srl(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("srl\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("srl\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = (ulong)reg.r[rs1] >> v;
+}
+
+void
+sra(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("sra\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("sra\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ if(reg.r[rs1]&SIGNBIT)
+ reg.r[rd] = reg.r[rs1]>>v | ~((1<<(32-v))-1);
+ else
+ reg.r[rd] = reg.r[rs1]>>v;
+}
+
+void
+subcc(ulong ir)
+{
+ long v;
+ int b31rs1, b31op2, b31res, r, rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("subcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("subcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] - v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ b31rs1 = reg.r[rs1]>>31;
+ b31op2 = v>>31;
+ b31res = r>>31;
+
+ if((b31rs1 & ~b31op2 & ~b31res)|(~b31rs1 & b31op2 & b31res))
+ reg.psr |= PSR_v;
+
+ if((~b31rs1 & b31op2)|(b31res & (~b31rs1|b31op2)))
+ reg.psr |= PSR_c;
+
+ reg.r[rd] = r;
+
+}
+
+void
+add(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("add\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("add\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] + v;
+}
+
+void
+addcc(ulong ir)
+{
+ long v, r;
+ int rd, rs1, rs2, b31rs1, b31op2, b31r;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("addcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("addcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] + v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ b31rs1 = reg.r[rs1]>>31;
+ b31op2 = v>>31;
+ b31r = r>>31;
+ if((b31rs1 & b31op2 & ~b31r)|(~b31rs1 & ~b31op2 & b31r))
+ reg.psr |= PSR_v;
+ if((b31rs1 & b31op2) | (~b31r & (b31rs1 | b31op2)))
+ reg.psr |= PSR_c;
+
+ reg.r[rd] = r;
+}
+
+void
+addx(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("addx\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("addx\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ if(reg.psr&PSR_c)
+ v++;
+ reg.r[rd] = reg.r[rs1] + v;
+}
+
+void
+addxcc(ulong ir)
+{
+ long r, v;
+ int rd, rs1, rs2, b31rs1, b31op2, b31r;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("addxcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("addxcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ if(reg.psr&PSR_c)
+ v++;
+
+ r = reg.r[rs1] + v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ b31rs1 = reg.r[rs1]>>31;
+ b31op2 = v>>31;
+ b31r = r>>31;
+ if((b31rs1 & b31op2 & ~b31r)|(~b31rs1 & ~b31op2 & b31r))
+ reg.psr |= PSR_v;
+ if((b31rs1 & b31op2) | (~b31r & (b31rs1 | b31op2)))
+ reg.psr |= PSR_c;
+
+ reg.r[rd] = r;
+}
+
+void
+wry(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(rd != 0)
+ undef(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("wry\tr%d,#0x%x,Y", rs1, v);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("wry\tr%d,r%d,Y", rs1, rs2);
+ }
+ reg.Y = reg.r[rs1] + v;
+}
+
+void
+rdy(ulong ir)
+{
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ USED(rs2);
+ if(rs1 != 0)
+ undef(ir);
+
+ if(trace)
+ itrace("rdy\tY,r%d", rd);
+
+ reg.r[rd] = reg.Y;
+}
+
+void
+and(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("and\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("and\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] & v;
+}
+
+void
+andcc(ulong ir)
+{
+ long v, r;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("andcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("andcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] & v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ reg.r[rd] = r;
+}
+
+void
+orcc(ulong ir)
+{
+ long v, r;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("orcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("orcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] | v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ reg.r[rd] = r;
+}
+
+void
+mulscc(ulong ir)
+{
+ int b, n, v, rd, rs1, rs2;
+ long o1, o2, r, b31o1, b31o2, b31r;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(o2, ir);
+ if(trace)
+ itrace("mulscc\tr%d,#0x%x,r%d", rs1, o2, rd);
+ }
+ else {
+ o2 = reg.r[rs2];
+ if(trace)
+ itrace("mulscc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ o1 = reg.r[rs1]>>1;
+ n = reg.psr&PSR_n ? 1 : 0;
+ v = reg.psr&PSR_v ? 1 : 0;
+
+ o1 |= (n ^ v)<<31;
+ if((reg.Y&1) == 0)
+ o2 = 0;
+
+ r = o1 + o2;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ b31o1 = o1>>31;
+ b31o2 = o2>>31;
+ b31r = r>>31;
+ if((b31o1 & b31o2 & ~b31r) | (~b31o1 & ~b31o2 & b31r))
+ reg.psr |= PSR_v;
+ if((b31o1 & b31o2) | (~b31r & (b31o1 | b31o2)))
+ reg.psr |= PSR_c;
+
+ b = reg.r[rs1]&1;
+ reg.Y = (reg.Y>>1)|(b<<31);
+ reg.r[rd] = r;
+}
+
+void
+or(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("or\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("or\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] | v;
+}
+
+void
+xor(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("xor\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("xor\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] ^ v;
+}
+
+void
+xorcc(ulong ir)
+{
+ long v, r;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("xorcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("xorcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] ^ v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ reg.r[rd] = r;
+}
+
+void
+andn(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("andn\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("andn\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] & ~v;
+}
+
+void
+andncc(ulong ir)
+{
+ long v, r;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("andncc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("andncc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] & ~v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ reg.r[rd] = r;
+}
+
+void
+orn(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(rd == 0 && rs1 == 0) /* ken used orn r0,r0,r0 as nop */
+ nopcount++;
+
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("orn\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("orn\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] | ~v;
+}
+
+void
+orncc(ulong ir)
+{
+ long r, v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("orncc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("orncc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] | ~v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ reg.r[rd] = r;
+}
+
+void
+xnor(ulong ir)
+{
+ long v;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("xnor\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("xnor\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ reg.r[rd] = reg.r[rs1] ^ ~v;
+}
+
+void
+xnorcc(ulong ir)
+{
+ long v, r;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(v, ir);
+ if(trace)
+ itrace("xnorcc\tr%d,#0x%x,r%d", rs1, v, rd);
+ }
+ else {
+ v = reg.r[rs2];
+ if(trace)
+ itrace("xnorcc\tr%d,r%d,r%d", rs1, rs2, rd);
+ }
+ r = reg.r[rs1] ^ ~v;
+ reg.psr &= ~(PSR_z|PSR_n|PSR_c|PSR_v);
+ if(r == 0)
+ reg.psr |= PSR_z;
+ if(r < 0)
+ reg.psr |= PSR_n;
+
+ reg.r[rd] = r;
+}
+
+void
+st(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("st\tr%d,0x%lux(r%d) %lux=%lux",
+ rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("st\tr%d,[r%d+r%d] %lux=%lux",
+ rd, rs1, rs2, ea, reg.r[rd]);
+ }
+
+ putmem_w(ea, reg.r[rd]);
+}
+
+void
+std(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("std\tr%d,0x%lux(r%d) %lux=%lux",
+ rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("std\tr%d,[r%d+r%d] %lux=%lux",
+ rd, rs1, rs2, ea, reg.r[rd]);
+ }
+
+ putmem_w(ea, reg.r[rd]);
+ putmem_w(ea+4, reg.r[rd+1]);
+}
+
+void
+stb(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("stb\tr%d,0x%lux(r%d) %lux=%lux",
+ rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]&0xff);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("stb\tr%d,[r%d+r%d] %lux=%lux",
+ rd, rs1, rs2, ea, reg.r[rd]&0xff);
+ }
+
+ putmem_b(ea, reg.r[rd]);
+}
+
+void
+sth(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("sth\tr%d,0x%lux(r%d) %lux=%lux",
+ rd, ea, rs1, ea+reg.r[rs1], reg.r[rd]&0xffff);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("sth\tr%d,[r%d+r%d] %lux=%lux",
+ rd, rs1, rs2, ea, reg.r[rd]&0xffff);
+ }
+
+ putmem_h(ea, reg.r[rd]);
+}
+
+void
+ld(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ld\tr%d,0x%lux(r%d) ea=%lux",rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ld\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = getmem_w(ea);
+ ilock(rd);
+}
+
+void
+swap(ulong ir)
+{
+ ulong t, ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("swap\tr%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("swap\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ t = reg.r[rd];
+ reg.r[rd] = getmem_w(ea);
+ putmem_w(ea, t);
+}
+
+void
+ldd(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ldd\tr%d,0x%lux(r%d) ea=%lux",rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ldd\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = getmem_w(ea);
+ reg.r[rd+1] = getmem_w(ea+4);
+}
+
+void
+ldub(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ldub\tr%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ldub\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = getmem_b(ea) & 0xff;
+ ilock(rd);
+}
+
+void
+ldstub(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ldstub\tr%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ldstub\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = getmem_b(ea) & 0xff;
+ putmem_b(ea, 0xff);
+}
+
+void
+ldsb(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ldsb\tr%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ldsb\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = (schar)getmem_b(ea);
+ ilock(rd);
+}
+
+void
+lduh(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("lduh\tr%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("lduh\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = getmem_h(ea) & 0xffff;
+ ilock(rd);
+}
+
+void
+ldsh(ulong ir)
+{
+ ulong ea;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ if(trace)
+ itrace("ldsh\tr%d,0x%lux(r%d) ea=%lux",
+ rd, ea, rs1, ea+reg.r[rs1]);
+ ea += reg.r[rs1];
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("ldsh\tr%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
+ }
+
+ reg.r[rd] = (short)getmem_h(ea);
+ ilock(rd);
+}
+
+void
+sethi(ulong ir)
+{
+ int rd;
+ ulong v;
+
+ rd = (ir>>25)&0x1f;
+ v = (ir&0x3FFFFF)<<10;
+
+ if(rd == 0)
+ nopcount++;
+
+ if(trace)
+ itrace("sethi\t0x%lux,r%d", v, rd);
+
+ reg.r[rd] = v;
+}
+
+void
+call(ulong ir)
+{
+ Symbol s;
+ ulong npc;
+
+ npc = (ir<<2) + reg.pc;
+ if(trace)
+ itrace("call\t%lux", npc);
+
+ ci->taken++;
+ reg.r[15] = reg.pc;
+ reg.ir = ifetch(reg.pc+4);
+ delay(npc);
+
+ if(calltree) {
+ findsym(npc, CTEXT, &s);
+ Bprint(bioout, "%8lux %s(", reg.pc, s.name);
+ printparams(&s, reg.r[1]);
+ Bprint(bioout, "from ");
+ printsource(reg.pc);
+ Bputc(bioout, '\n');
+ }
+ npc -= 4;
+ reg.pc = npc;
+}
+
+void
+jmpl(ulong ir)
+{
+ ulong ea, o;
+ Symbol s;
+ int rd, rs1, rs2;
+
+ getrop23(ir);
+ if(ir&IMMBIT) {
+ ximm(ea, ir);
+ o = ea;
+ if(trace)
+ itrace("jmpl\t0x%lux(r%d),r%d", ea, rs1, rd);
+
+ ea += reg.r[rs1];
+ if(calltree && rd == 0 && o == 8) {
+ findsym(ea-4, CTEXT, &s);
+ Bprint(bioout, "%8lux return to %lux %s r7=%lux\n",
+ reg.pc, ea-4, s.name, reg.r[7]);
+ }
+ }
+ else {
+ ea = reg.r[rs1] + reg.r[rs2];
+ if(trace)
+ itrace("jmpl\t[r%d+r%d],r%d", rs1, rs2, rd);
+ }
+
+ ci->taken++;
+ reg.r[rd] = reg.pc;
+ reg.ir = ifetch(reg.pc+4);
+ delay(ea);
+ reg.pc = ea-4;
+}
+
+void
+bicc(ulong ir)
+{
+ char *op;
+ ulong npc, anul, ba;
+ int takeit, z, v, n, c;
+
+ SET(op, takeit);
+ ba = 0;
+ switch((ir>>25)&0x0F) {
+ case 0:
+ op = "bn";
+ takeit = 0;
+ break;
+ case 1:
+ op = "be";
+ takeit = reg.psr&PSR_z;
+ break;
+ case 2:
+ op = "ble";
+ z = reg.psr&PSR_z ? 1 : 0;
+ v = reg.psr&PSR_v ? 1 : 0;
+ n = reg.psr&PSR_n ? 1 : 0;
+ takeit = z | (n ^ v);
+ break;
+ case 3:
+ op = "bl";
+ v = reg.psr&PSR_v ? 1 : 0;
+ n = reg.psr&PSR_n ? 1 : 0;
+ takeit = n ^ v;
+ break;
+ case 4:
+ op = "bleu";
+ z = reg.psr&PSR_z ? 1 : 0;
+ c = reg.psr&PSR_c ? 1 : 0;
+ takeit = c | z;
+ break;
+ case 5:
+ op = "bcs";
+ takeit = reg.psr&PSR_c;
+ break;
+ case 6:
+ op = "bneg";
+ takeit = reg.psr&PSR_n;
+ break;
+ case 7:
+ op = "bvs";
+ takeit = reg.psr&PSR_v;
+ break;
+ case 8:
+ op = "ba";
+ ba = 1;
+ takeit = 1;
+ break;
+ case 9:
+ op = "bne";
+ takeit = !(reg.psr&PSR_z);
+ break;
+ case 10:
+ op = "bg";
+ z = reg.psr&PSR_z ? 1 : 0;
+ v = reg.psr&PSR_v ? 1 : 0;
+ n = reg.psr&PSR_n ? 1 : 0;
+ takeit = !(z | (n ^ v));
+ break;
+ case 11:
+ op = "bge";
+ v = reg.psr&PSR_v ? 1 : 0;
+ n = reg.psr&PSR_n ? 1 : 0;
+ takeit = !(n ^ v);
+ break;
+ case 12:
+ op = "bgu";
+ z = reg.psr&PSR_z ? 1 : 0;
+ c = reg.psr&PSR_c ? 1 : 0;
+ takeit = !(c | z);
+ break;
+ case 13:
+ op = "bcc";
+ takeit = !(reg.psr&PSR_c);
+ break;
+ case 14:
+ op = "bpos";
+ takeit = !(reg.psr&PSR_n);
+ break;
+ case 15:
+ op = "bvc";
+ takeit = !(reg.psr&PSR_v);
+ break;
+ }
+
+ npc = ir & 0x3FFFFF;
+ if(npc & (1<<21))
+ npc |= ~((1<<22)-1);
+ npc = (npc<<2) + reg.pc;
+
+ anul = ir&ANUL;
+ if(trace) {
+ if(anul)
+ itrace("%s,a\t%lux", op, npc);
+ else
+ itrace("%s\t%lux", op, npc);
+ }
+
+ if(takeit == 0) {
+ reg.pc += 4;
+ if(anul == 0) {
+ reg.ir = ifetch(reg.pc);
+ delay(reg.pc+4);
+ }
+ else
+ anulled++;
+ return;
+ }
+
+ ci->taken++;
+ if(ba && anul) {
+ anulled++;
+ reg.pc = npc-4;
+ return;
+ }
+ reg.ir = ifetch(reg.pc+4);
+ delay(npc);
+ reg.pc = npc-4;
+}
diff --git a/sys/src/cmd/ki/sparc.h b/sys/src/cmd/ki/sparc.h
new file mode 100755
index 000000000..1501f9e0f
--- /dev/null
+++ b/sys/src/cmd/ki/sparc.h
@@ -0,0 +1,236 @@
+/*
+ * sparc sim.h
+ *
+ * The integer instruction side of this emulator is portable if sizeof(long) >= 4
+ * Floating point emulation however is not. Assumptions made are:
+ * sizeof(ulong) == sizeof(float)
+ * sizeof(ulong)*2 == sizeof(double)
+ * bits of floating point in memory may be reversed lsw/msw
+ * unions of double & 2*float & 2*long have no padding
+ */
+#include "/sparc/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 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,
+ Inop,
+};
+
+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 Y;
+ ulong psr;
+ ulong fpsr;
+
+ union {
+ double fd[16];
+ float fl[32];
+ ulong di[32];
+ };
+};
+
+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);
+void itrace(char *, ...);
+void segsum(void);
+void ta(ulong);
+char* memio(char*, ulong, int, int);
+ulong getmem_w(ulong);
+ulong ifetch(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);
+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 initstk(int, char**);
+void initmap(void);
+void inithdr(int);
+void reset(void);
+void dobplist(void);
+void procinit(int);
+void printsource(long);
+void printparams(Symbol *, ulong);
+void printlocals(Symbol *, ulong);
+void stktrace(int);
+void delay(ulong);
+void iprofile(void);
+
+/* Globals */
+Extern Registers reg;
+Extern Memory memory;
+Extern int text;
+Extern int trace;
+Extern int sysdbg;
+Extern int calltree;
+Extern Icache icache;
+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 Inst *ci;
+Extern ulong *iprof;
+Extern ulong loadlock;
+Extern ulong anulled;
+extern int datasize;
+extern int printcol;
+Extern Map *symmap;
+
+/* Plan9 Kernel constants */
+#define BY2PG 4096
+#define BY2WD 4
+#define UTZERO 0x1000
+#define TSTKSIZ 32
+#define TSTACKTOP 0x10000000
+#define STACKTOP (TSTACKTOP-TSTKSIZ*BY2PG)
+#define STACKSIZE (4*1024*1024)
+
+#define ANUL (1<<29)
+#define PROFGRAN 4
+#define NOP 0x80300000
+#define SIGNBIT 0x80000000
+#define IMMBIT (1<<13)
+#define getrop23(i) rd = (i>>25)&0x1f; rs1 = (i>>14)&0x1f; rs2 = i&0x1f;
+#define ximm(xx, ii) xx = ii&0x1FFF; if(xx&0x1000) xx |= ~0x1FFF
+
+#define PSR_n (1<<23)
+#define PSR_z (1<<22)
+#define PSR_v (1<<21)
+#define PSR_c (1<<20)
+
+#define FP_U 3
+#define FP_L 1
+#define FP_G 2
+#define FP_E 0
diff --git a/sys/src/cmd/ki/stats.c b/sys/src/cmd/ki/stats.c
new file mode 100755
index 000000000..dc441e692
--- /dev/null
+++ b/sys/src/cmd/ki/stats.c
@@ -0,0 +1,214 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.h"
+
+#define prof profki
+#define Percent(num, max) (((num)*100)/(max))
+
+extern Inst op0[], op2[], op3[];
+Inst *tables[] = { op0, op2, op3, 0 };
+
+void
+isum(void)
+{
+ Inst *i;
+ int pct, j;
+ int total, loads, stores, arith, branch;
+ int useddelay, taken, sparcreg, syscall, realarith;
+
+ total = 0;
+ loads = 0;
+ stores = 0;
+ arith = 0;
+ branch = 0;
+ useddelay = 0;
+ taken = 0;
+ sparcreg = 0;
+ syscall = 0;
+ realarith = 0;
+
+ /* 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)
+ 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) {
+ 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:
+ sparcreg += i->count;
+ break;
+ case Isyscall:
+ syscall += i->count;
+ break;
+ case Ifloat:
+ realarith += i->count;
+ break;
+ case Inop:
+ arith += i->count;
+ i->count -= nopcount;
+ break;
+ }
+ }
+ }
+ }
+
+ total += anulled;
+ 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, "%-8lud %3ld%% Annulled branch cycles\n",
+ anulled, Percent(anulled, 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));
+
+ Bprint(bioout, " %-8ud Store stall\n", stores*2);
+
+ Bprint(bioout, " %-8lud Load stall\n", loadlock);
+
+ 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%% Sparc special register load/stores\n",
+ sparcreg, Percent(sparcreg, 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",
+ nopcount, Percent(nopcount, branch));
+
+ Bprint(bioout, "%-8ud %3d%% Program total delay slots\n",
+ nopcount, Percent(nopcount, total));
+}
+
+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/ki/symbols.c b/sys/src/cmd/ki/symbols.c
new file mode 100755
index 000000000..8c23d5c14
--- /dev/null
+++ b/sys/src/cmd/ki/symbols.c
@@ -0,0 +1,97 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.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[1];
+ 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[15];
+ 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/ki/syscall.c b/sys/src/cmd/ki/syscall.c
new file mode 100755
index 000000000..685ccabf5
--- /dev/null
+++ b/sys/src/cmd/ki/syscall.c
@@ -0,0 +1,729 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "sparc.h"
+
+#define REGSP 1
+#define REGRET 7
+
+
+#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",
+ [PREAD] "Pread",
+ [PWRITE] "Pwrite",
+ [AWAIT] "Await",
+};
+
+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 sysawait(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+void sysfversion(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); }
+void sys_fsession(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 sys_wait(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 (*systab[])(void) ={
+ [SYSR1] sys1,
+ [_ERRSTR] sys_errstr,
+ [BIND] sysbind,
+ [CHDIR] syschdir,
+ [CLOSE] sysclose,
+ [DUP] sysdup,
+ [ALARM] sysalarm,
+ [EXEC] sysexec,
+ [EXITS] sysexits,
+ [_FSESSION] sys_fsession,
+ [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] sys_wait,
+ [SEEK] sysseek,
+ [FVERSION] sysfversion,
+ [ERRSTR] syserrstr,
+ [STAT] sysstat,
+ [FSTAT] sysfstat,
+ [WSTAT] syswstat,
+ [FWSTAT] sysfwstat,
+ [PREAD] syspread,
+ [PWRITE] syspwrite,
+ [AWAIT] sysawait,
+};
+
+void
+ta(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("ta\t$0+R0\t%s", sysctab[call]);
+
+ (*systab[call])();
+ Bflush(bioout);
+}