summaryrefslogtreecommitdiff
path: root/sys/src/cmd/5i
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/5i
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/5i')
-rwxr-xr-xsys/src/cmd/5i/5i.c270
-rwxr-xr-xsys/src/cmd/5i/arm.h240
-rwxr-xr-xsys/src/cmd/5i/bpt.c128
-rwxr-xr-xsys/src/cmd/5i/cmd.c635
-rwxr-xr-xsys/src/cmd/5i/float.c203
-rwxr-xr-xsys/src/cmd/5i/icache.c17
-rwxr-xr-xsys/src/cmd/5i/mem.c285
-rwxr-xr-xsys/src/cmd/5i/mkfile26
-rwxr-xr-xsys/src/cmd/5i/run.c948
-rwxr-xr-xsys/src/cmd/5i/stats.c199
-rwxr-xr-xsys/src/cmd/5i/symbols.c95
-rwxr-xr-xsys/src/cmd/5i/syscall.c807
12 files changed, 3853 insertions, 0 deletions
diff --git a/sys/src/cmd/5i/5i.c b/sys/src/cmd/5i/5i.c
new file mode 100755
index 000000000..554a9f2cc
--- /dev/null
+++ b/sys/src/cmd/5i/5i.c
@@ -0,0 +1,270 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.h"
+
+#include <tos.h>
+
+char* file = "5.out";
+int datasize;
+ulong textbase;
+Biobuf bp, bi;
+Fhdr fhdr;
+
+void
+main(int argc, char **argv)
+{
+
+ argc--;
+ argv++;
+
+ bioout = &bp;
+ bin = &bi;
+ Binit(bioout, 1, OWRITE);
+ Binit(bin, 0, OREAD);
+
+ tlb.on = 1;
+ tlb.tlbsize = 24;
+
+ if(argc)
+ file = argv[0];
+ argc--;
+ argv++;
+
+ text = open(file, OREAD);
+ if(text < 0)
+ fatal(1, "open text '%s'", file);
+
+ Bprint(bioout, "5i\n");
+ inithdr(text);
+ initstk(argc, argv);
+
+ 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.r[REGPC] = fhdr.entry;
+}
+
+void
+inithdr(int fd)
+{
+ Symbol s;
+
+ extern Machdata armmach;
+
+ seek(fd, 0, 0);
+ if (!crackhdr(fd, &fhdr))
+ fatal(0, "read text header");
+
+ if(fhdr.type != FARM )
+ fatal(0, "bad magic number: %d %d", fhdr.type, FARM);
+
+ 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 = &armmach;
+}
+
+void
+reset(void)
+{
+ int i, l, m;
+ Segment *s;
+ Breakpoint *b;
+
+ memset(&reg, 0, sizeof(Registers));
+
+ 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, tos;
+ int i;
+ char *p;
+
+ initmap();
+ tos = STACKTOP - sizeof(Tos)*2; /* we'll assume twice the host's is big enough */
+ sp = tos;
+
+ /* 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 &= ~7;
+ reg.r[0] = tos;
+ reg.r[13] = 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 = "5i: %s\n";
+ if(syserr)
+ s = "5i: %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 %2d %s\n", reg.ar, reg.ir, reg.class, buf);
+}
+
+void
+dumpreg(void)
+{
+ int i;
+
+ Bprint(bioout, "PC #%-8lux SP #%-8lux \n",
+ reg.r[REGPC], reg.r[REGSP]);
+
+ for(i = 0; i < 16; 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)
+{
+}
+
+void
+dumpdreg(void)
+{
+}
+
+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;
+}
diff --git a/sys/src/cmd/5i/arm.h b/sys/src/cmd/5i/arm.h
new file mode 100755
index 000000000..322bcb2be
--- /dev/null
+++ b/sys/src/cmd/5i/arm.h
@@ -0,0 +1,240 @@
+/*
+ * arm.h
+ */
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+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
+{
+ Imem,
+ Iarith,
+ Ibranch,
+ Isyscall,
+};
+
+enum
+{
+ Nmaxtlb = 64,
+ REGARG = 0,
+ REGRET = 0,
+ REGPC = 15,
+ REGLINK = 14,
+ REGSP = 13,
+};
+
+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 ar;
+ ulong ir;
+ Inst* ip;
+ long r[16];
+ long cc1;
+ long cc2;
+ int class;
+ int cond;
+ int compare_op;
+ int cbit;
+ int cout;
+};
+
+enum
+{
+ FPd = 0,
+ FPs,
+ FPmemory,
+};
+
+enum
+{
+ MemRead,
+ MemReadstring,
+ MemWrite,
+};
+
+enum
+{
+ CCcmp,
+ CCtst,
+ CCteq,
+};
+
+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 Ssyscall(ulong);
+int armclass(long);
+void breakpoint(char*, char*);
+void brkchk(ulong, int);
+void cmd(void);
+void delbpt(char*);
+void dobplist(void);
+void dumpdreg(void);
+void dumpfreg(void);
+void dumpreg(void);
+void* emalloc(ulong);
+void* erealloc(void*, ulong, ulong);
+ulong expr(char*);
+void fatal(int, char*, ...);
+ulong getmem_2(ulong);
+ulong getmem_4(ulong);
+uchar getmem_b(ulong);
+ushort getmem_h(ulong);
+uvlong getmem_v(ulong);
+ulong getmem_w(ulong);
+ulong ifetch(ulong);
+void inithdr(int);
+void initicache(void);
+void initmap(void);
+void initstk(int, char**);
+void iprofile(void);
+void isum(void);
+void itrace(char*, ...);
+long lnrand(long);
+char* memio(char*, ulong, int, int);
+int _mipscoinst(Map*, ulong, char*, int);
+Mul mul(long, long);
+Mulu mulu(ulong, ulong);
+char* nextc(char*);
+void printlocals(Symbol*, ulong);
+void printparams(Symbol*, ulong);
+void printsource(long);
+void procinit(int);
+void putmem_b(ulong, uchar);
+void putmem_h(ulong, ushort);
+void putmem_v(ulong, uvlong);
+void putmem_w(ulong, ulong);
+void reset(void);
+void run(void);
+void segsum(void);
+void stktrace(int);
+void tlbsum(void);
+void undef(ulong);
+void updateicache(ulong addr);
+void* vaddr(ulong);
+
+/* 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;
+
+/* Plan9 Kernel constants */
+enum
+{
+ BY2PG = 4096,
+ BY2WD = 4,
+ UTZERO = 0x1000,
+ STACKTOP = 0x80000000,
+ STACKSIZE = 0x10000,
+
+ PROFGRAN = 4,
+ Sbit = 1<<20,
+ SIGNBIT = 0x80000000,
+
+ FP_U = 3,
+ FP_L = 1,
+ FP_G = 2,
+ FP_E = 0,
+ FP_CBIT = 1<<23,
+};
diff --git a/sys/src/cmd/5i/bpt.c b/sys/src/cmd/5i/bpt.c
new file mode 100755
index 000000000..2f9362071
--- /dev/null
+++ b/sys/src/cmd/5i/bpt.c
@@ -0,0 +1,128 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include <ctype.h>
+#include "arm.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/5i/cmd.c b/sys/src/cmd/5i/cmd.c
new file mode 100755
index 000000000..c27e5adf5
--- /dev/null
+++ b/sys/src/cmd/5i/cmd.c
@@ -0,0 +1,635 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include <ctype.h>
+#include "arm.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.r[15];
+ 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':
+ 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[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[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':
+ case 'i':
+ inc = machdata->das(symmap, dot, fmt, str, sizeof(str));
+ if(inc < 0) {
+ Bprint(bioout, "5i: %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)
+{
+ static int hit = 0;
+
+ hit++;
+ if(hit > 5)
+ exits(0);
+ USED(a);
+ if(strcmp(msg, "interrupt") != 0)
+ noted(NDFLT);
+
+ count = 1;
+ print("5i\n");
+ noted(NCONT);
+}
+
+void
+setreg(char *addr, char *cp)
+{
+ int rn;
+
+ dot = expr(addr);
+ cp = nextc(cp);
+ if(strcmp(cp, "pc") == 0) {
+ reg.r[15] = dot;
+ return;
+ }
+ if(strcmp(cp, "sp") == 0) {
+ reg.r[13] = dot;
+ return;
+ }
+ if(*cp++ == 'r') {
+ rn = strtoul(cp, 0, 10);
+ if(rn > 0 && rn < 16) {
+ 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.r[15];
+ 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/5i/float.c b/sys/src/cmd/5i/float.c
new file mode 100755
index 000000000..958df2e9f
--- /dev/null
+++ b/sys/src/cmd/5i/float.c
@@ -0,0 +1,203 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.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 %d\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.r[15]);
+ longjmp(errjmp, 0);
+}
+
+void
+floatop(int dst, int s1, int s2)
+{
+}
+
+void
+doubop(int dst, int s1, int s2)
+{
+}
+
+void
+Iswc1(ulong inst)
+{
+}
+
+void
+Ifsub(ulong ir)
+{
+}
+
+void
+Ifmov(ulong ir)
+{
+}
+
+void
+Ifabs(ulong ir)
+{
+}
+
+void
+Ifneg(ulong ir)
+{
+}
+
+void
+Icvtd(ulong ir)
+{
+}
+
+void
+Icvts(ulong ir)
+{
+}
+
+void
+Icvtw(ulong ir)
+{
+}
+
+void
+Ifadd(ulong ir)
+{
+}
+
+void
+Ifmul(ulong ir)
+{
+}
+
+void
+Ifdiv(ulong ir)
+{
+}
+
+void
+Ilwc1(ulong inst)
+{
+}
+
+void
+Ibcfbct(ulong inst)
+{
+}
+
+void
+Imtct(ulong ir)
+{
+}
+
+void
+Imfcf(ulong ir)
+{
+}
+
+void
+Icop1(ulong ir)
+{
+}
+
+void
+Ifcmp(ulong ir)
+{
+}
diff --git a/sys/src/cmd/5i/icache.c b/sys/src/cmd/5i/icache.c
new file mode 100755
index 000000000..131064126
--- /dev/null
+++ b/sys/src/cmd/5i/icache.c
@@ -0,0 +1,17 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.h"
+
+void
+icacheinit(void)
+{
+}
+
+void
+updateicache(ulong addr)
+{
+ USED(addr);
+}
+
diff --git a/sys/src/cmd/5i/mem.c b/sys/src/cmd/5i/mem.c
new file mode 100755
index 000000000..5690bd312
--- /dev/null
+++ b/sys/src/cmd/5i/mem.c
@@ -0,0 +1,285 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.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[3]<<24 | va[2]<<16 | va[1]<<8 | va[0];
+}
+
+ulong
+getmem_4(ulong addr)
+{
+ ulong val;
+ int i;
+
+ val = 0;
+ for(i = 0; i < 4; i++)
+ val = (val>>8) | (getmem_b(addr++)<<24);
+ return val;
+}
+
+ulong
+getmem_2(ulong addr)
+{
+ ulong val;
+ int i;
+
+ val = 0;
+ for(i = 0; i < 2; i++)
+ val = (val>>8) | (getmem_b(addr++)<<16);
+ return val;
+}
+
+ulong
+getmem_w(ulong addr)
+{
+ uchar *va;
+ ulong w;
+
+ if(addr&3) {
+ w = getmem_w(addr & ~3);
+ while(addr & 3) {
+ w = (w>>8) | (w<<24);
+ addr--;
+ }
+ return w;
+ }
+ if(membpt)
+ brkchk(addr, Read);
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+
+ return va[3]<<24 | va[2]<<16 | va[1]<<8 | va[0];
+}
+
+ushort
+getmem_h(ulong addr)
+{
+ uchar *va;
+ ulong w;
+
+ if(addr&1) {
+ w = getmem_h(addr & ~1);
+ while(addr & 1) {
+ w = (w>>8) | (w<<8);
+ addr--;
+ }
+ return w;
+ }
+ if(membpt)
+ brkchk(addr, Read);
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+
+ return va[1]<<8 | va[0];
+}
+
+uchar
+getmem_b(ulong addr)
+{
+ uchar *va;
+
+ if(membpt)
+ brkchk(addr, Read);
+
+ va = vaddr(addr);
+ va += addr&(BY2PG-1);
+ return va[0];
+}
+
+uvlong
+getmem_v(ulong addr)
+{
+ return ((uvlong)getmem_w(addr+4) << 32) | getmem_w(addr);
+}
+
+void
+putmem_h(ulong addr, ushort 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[1] = data>>8;
+ va[0] = data;
+ if(membpt)
+ brkchk(addr, Write);
+}
+
+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[3] = data>>24;
+ va[2] = data>>16;
+ va[1] = data>>8;
+ va[0] = 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_v(ulong addr, uvlong data)
+{
+ putmem_w(addr, data); /* two stages, to catch brkchk */
+ putmem_w(addr+4, data>>32);
+}
+
+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 arm\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 *
+vaddr(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;
+ }
+ }
+ }
+ Bprint(bioout, "User TLB miss vaddr 0x%.8lux\n", addr);
+ longjmp(errjmp, 0);
+ return 0; /*to stop compiler whining*/
+}
diff --git a/sys/src/cmd/5i/mkfile b/sys/src/cmd/5i/mkfile
new file mode 100755
index 000000000..f4060795f
--- /dev/null
+++ b/sys/src/cmd/5i/mkfile
@@ -0,0 +1,26 @@
+</$objtype/mkfile
+
+TARG=5i
+OFILES= 5i.$O\
+ run.$O\
+ mem.$O\
+ syscall.$O\
+ stats.$O\
+ icache.$O\
+ symbols.$O\
+ cmd.$O\
+ bpt.$O\
+
+HFILES=arm.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/5i/run.c b/sys/src/cmd/5i/run.c
new file mode 100755
index 000000000..0454ea6de
--- /dev/null
+++ b/sys/src/cmd/5i/run.c
@@ -0,0 +1,948 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.h"
+
+static int dummy;
+static char* shtype[4] =
+{
+ "<<",
+ ">>",
+ "->",
+ "@>",
+};
+static char* cond[16] =
+{
+ ".EQ", ".NE", ".HS", ".LO",
+ ".MI", ".PL", ".VS", ".VC",
+ ".HI", ".LS", ".GE", ".LT",
+ ".GT", ".LE", "", ".NO",
+};
+
+void Idp0(ulong);
+void Idp1(ulong);
+void Idp2(ulong);
+void Idp3(ulong);
+
+void Imul(ulong);
+void Imula(ulong);
+void Imull(ulong);
+
+void Iswap(ulong);
+void Imem1(ulong);
+void Imem2(ulong);
+void Ilsm(ulong inst);
+
+void Ib(ulong);
+void Ibl(ulong);
+
+void Ssyscall(ulong);
+
+Inst itab[] =
+{
+ { Idp0, "AND", Iarith }, /* 00 - r,r,r */
+ { Idp0, "EOR", Iarith }, /* 01 */
+ { Idp0, "SUB", Iarith }, /* 02 */
+ { Idp0, "RSB", Iarith }, /* 03 */
+ { Idp0, "ADD", Iarith }, /* 04 */
+ { Idp0, "ADC", Iarith }, /* 05 */
+ { Idp0, "SBC", Iarith }, /* 06 */
+ { Idp0, "RSC", Iarith }, /* 07 */
+ { Idp0, "TST", Iarith }, /* 08 */
+ { Idp0, "TEQ", Iarith }, /* 09 */
+
+ { Idp0, "CMP", Iarith }, /* 10 */
+ { Idp0, "CMN", Iarith }, /* 11 */
+ { Idp0, "ORR", Iarith }, /* 12 */
+ { Idp0, "MOV", Iarith }, /* 13 */
+ { Idp0, "BIC", Iarith }, /* 14 */
+ { Idp0, "MVN", Iarith }, /* 15 */
+ { Idp1, "AND", Iarith }, /* 16 */
+ { Idp1, "EOR", Iarith }, /* 17 */
+ { Idp1, "SUB", Iarith }, /* 18 */
+ { Idp1, "RSB", Iarith }, /* 19 */
+
+ { Idp1, "ADD", Iarith }, /* 20 */
+ { Idp1, "ADC", Iarith }, /* 21 */
+ { Idp1, "SBC", Iarith }, /* 22 */
+ { Idp1, "RSC", Iarith }, /* 23 */
+ { Idp1, "TST", Iarith }, /* 24 */
+ { Idp1, "TEQ", Iarith }, /* 25 */
+ { Idp1, "CMP", Iarith }, /* 26 */
+ { Idp1, "CMN", Iarith }, /* 27 */
+ { Idp1, "ORR", Iarith }, /* 28 */
+ { Idp1, "MOV", Iarith }, /* 29 */
+
+ { Idp1, "BIC", Iarith }, /* 30 */
+ { Idp1, "MVN", Iarith }, /* 31 */
+ { Idp2, "AND", Iarith }, /* 32 */
+ { Idp2, "EOR", Iarith }, /* 33 */
+ { Idp2, "SUB", Iarith }, /* 34 */
+ { Idp2, "RSB", Iarith }, /* 35 */
+ { Idp2, "ADD", Iarith }, /* 36 */
+ { Idp2, "ADC", Iarith }, /* 37 */
+ { Idp2, "SBC", Iarith }, /* 38 */
+ { Idp2, "RSC", Iarith }, /* 39 */
+
+ { Idp2, "TST", Iarith }, /* 40 */
+ { Idp2, "TEQ", Iarith }, /* 41 */
+ { Idp2, "CMP", Iarith }, /* 42 */
+ { Idp2, "CMN", Iarith }, /* 43 */
+ { Idp2, "ORR", Iarith }, /* 44 */
+ { Idp2, "MOV", Iarith }, /* 45 */
+ { Idp2, "BIC", Iarith }, /* 46 */
+ { Idp2, "MVN", Iarith }, /* 47 */
+ { Idp3, "AND", Iarith }, /* 48 - i,r,r */
+ { Idp3, "EOR", Iarith }, /* 49 */
+
+ { Idp3, "SUB", Iarith }, /* 50 */
+ { Idp3, "RSB", Iarith }, /* 51 */
+ { Idp3, "ADD", Iarith }, /* 52 */
+ { Idp3, "ADC", Iarith }, /* 53 */
+ { Idp3, "SBC", Iarith }, /* 54 */
+ { Idp3, "RSC", Iarith }, /* 55 */
+ { Idp3, "TST", Iarith }, /* 56 */
+ { Idp3, "TEQ", Iarith }, /* 57 */
+ { Idp3, "CMP", Iarith }, /* 58 */
+ { Idp3, "CMN", Iarith }, /* 59 */
+
+ { Idp3, "ORR", Iarith }, /* 60 */
+ { Idp3, "MOV", Iarith }, /* 61 */
+ { Idp3, "BIC", Iarith }, /* 62 */
+ { Idp3, "MVN", Iarith }, /* 63 */
+ { Imul, "MUL", Iarith }, /* 64 */
+ { Imula, "MULA", Iarith }, /* 65 */
+
+ { Iswap, "SWPW", Imem }, /* 66 */
+ { Iswap, "SWPBU", Imem }, /* 67 */
+
+ { Imem2, "MOV", Imem }, /* 68 load/store h/sb */
+ { Imem2, "MOV", Imem }, /* 69 */
+ { Imem2, "MOV", Imem }, /* 70 */
+ { Imem2, "MOV", Imem }, /* 71 */
+
+ { Imem1, "MOVW", Imem }, /* 72 load/store w/ub i,r */
+ { Imem1, "MOVB", Imem }, /* 73 */
+ { Imem1, "MOVW", Imem }, /* 74 */
+ { Imem1, "MOVB", Imem }, /* 75 */
+ { Imem1, "MOVW", Imem }, /* 76 load/store r,r */
+ { Imem1, "MOVB", Imem }, /* 77 */
+ { Imem1, "MOVW", Imem }, /* 78 */
+ { Imem1, "MOVB", Imem }, /* 79 */
+
+ { Ilsm, "LDM", Imem }, /* 80 block move r,r */
+ { Ilsm, "STM", Imem }, /* 81 */
+ { Ib, "B", Ibranch }, /* 82 branch */
+ { Ibl, "BL", Ibranch }, /* 83 */
+ { Ssyscall, "SWI", Isyscall }, /* 84 co processor */
+ { undef, "undef" }, /* 85 */
+ { undef, "undef" }, /* 86 */
+ { undef, "undef" }, /* 87 */
+ { Imull, "MULLU", Iarith }, /* 88 */
+ { Imull, "MULALU", Iarith }, /* 89 */
+ { Imull, "MULL", Iarith }, /* 90 */
+ { Imull, "MULAL", Iarith }, /* 91 */
+ { undef, "undef" }, /* 92 */
+
+ { 0 }
+};
+
+int
+runcmp(void)
+{
+ switch(reg.cond) {
+ case 0x0: /* eq */ return (reg.cc1 == reg.cc2);
+ case 0x1: /* ne */ return (reg.cc1 != reg.cc2);
+ case 0x2: /* hs */ return ((ulong)reg.cc1 >= (ulong)reg.cc2);
+ case 0x3: /* lo */ return ((ulong)reg.cc1 < (ulong)reg.cc2);
+ case 0x4: /* mi */ return (reg.cc1 - reg.cc2 < 0);
+ case 0x5: /* pl */ return (reg.cc1 - reg.cc2 >= 0);
+ case 0x8: /* hi */ return ((ulong)reg.cc1 > (ulong)reg.cc2);
+ case 0x9: /* ls */ return ((ulong)reg.cc1 <= (ulong)reg.cc2);
+ case 0xa: /* ge */ return (reg.cc1 >= reg.cc2);
+ case 0xb: /* lt */ return (reg.cc1 < reg.cc2);
+ case 0xc: /* gt */ return (reg.cc1 > reg.cc2);
+ case 0xd: /* le */ return (reg.cc1 <= reg.cc2);
+ case 0xe: /* al */ return 1;
+ case 0xf: /* nv */ return 0;
+ default:
+ Bprint(bioout, "unimplemented condition prefix %x (%ld %ld)\n",
+ reg.cond, reg.cc1, reg.cc2);
+ undef(reg.ir);
+ return 0;
+ }
+}
+
+int
+runteq(void)
+{
+ long res = reg.cc1 ^ reg.cc2;
+ switch(reg.cond) {
+ case 0x0: /* eq */ return res == 0;
+ case 0x1: /* ne */ return res != 0;
+ case 0x4: /* mi */ return (res & SIGNBIT) != 0;
+ case 0x5: /* pl */ return (res & SIGNBIT) == 0;
+ case 0xe: /* al */ return 1;
+ case 0xf: /* nv */ return 0;
+ default:
+ Bprint(bioout, "unimplemented condition prefix %x (%ld %ld)\n",
+ reg.cond, reg.cc1, reg.cc2);
+ undef(reg.ir);
+ return 0;
+ }
+}
+
+int
+runtst(void)
+{
+ long res = reg.cc1 & reg.cc2;
+ switch(reg.cond) {
+ case 0x0: /* eq */ return res == 0;
+ case 0x1: /* ne */ return res != 0;
+ case 0x4: /* mi */ return (res & SIGNBIT) != 0;
+ case 0x5: /* pl */ return (res & SIGNBIT) == 0;
+ case 0xe: /* al */ return 1;
+ case 0xf: /* nv */ return 0;
+ default:
+ Bprint(bioout, "unimplemented condition prefix %x (%ld %ld)\n",
+ reg.cond, reg.cc1, reg.cc2);
+ undef(reg.ir);
+ return 0;
+ }
+}
+
+void
+run(void)
+{
+ int execute;
+
+ do {
+ if(trace)
+ Bflush(bioout);
+ reg.ar = reg.r[REGPC];
+ reg.ir = ifetch(reg.ar);
+ reg.class = armclass(reg.ir);
+ reg.ip = &itab[reg.class];
+ reg.cond = (reg.ir>>28) & 0xf;
+ switch(reg.compare_op) {
+ case CCcmp:
+ execute = runcmp();
+ break;
+ case CCteq:
+ execute = runteq();
+ break;
+ case CCtst:
+ execute = runtst();
+ break;
+ default:
+ Bprint(bioout, "unimplemented compare operation %x\n",
+ reg.compare_op);
+ return;
+ }
+
+ if(execute) {
+ reg.ip->count++;
+ (*reg.ip->func)(reg.ir);
+ } else {
+ if(trace)
+ itrace("%s%s IGNORED",
+ reg.ip->name, cond[reg.cond]);
+ }
+ reg.r[REGPC] += 4;
+ if(bplist)
+ brkchk(reg.r[REGPC], Instruction);
+ } while(--count);
+}
+
+void
+undef(ulong inst)
+{
+ Bprint(bioout, "undefined instruction trap pc #%lux inst %.8lux class %d\n",
+ reg.r[REGPC], inst, reg.class);
+ longjmp(errjmp, 0);
+}
+
+long
+shift(long v, int st, int sc, int isreg)
+{
+ if(sc == 0) {
+ switch(st) {
+ case 0: /* logical left */
+ reg.cout = reg.cbit;
+ break;
+ case 1: /* logical right */
+ reg.cout = (v >> 31) & 1;
+ break;
+ case 2: /* arith right */
+ reg.cout = reg.cbit;
+ break;
+ case 3: /* rotate right */
+ if(isreg) {
+ reg.cout = reg.cbit;
+ }
+ else {
+ reg.cout = v & 1;
+ v = ((ulong)v >> 1) | (reg.cbit << 31);
+ }
+ }
+ }
+ else {
+ switch(st) {
+ case 0: /* logical left */
+ reg.cout = (v >> (32 - sc)) & 1;
+ v = v << sc;
+ break;
+ case 1: /* logical right */
+ reg.cout = (v >> (sc - 1)) & 1;
+ v = (ulong)v >> sc;
+ break;
+ case 2: /* arith right */
+ if(sc >= 32) {
+ reg.cout = (v >> 31) & 1;
+ if(reg.cout)
+ v = 0xFFFFFFFF;
+ else
+ v = 0;
+ }
+ else {
+ reg.cout = (v >> (sc - 1)) & 1;
+ v = (long)v >> sc;
+ }
+ break;
+ case 3: /* rotate right */
+ reg.cout = (v >> (sc - 1)) & 1;
+ v = (v << (32-sc)) | ((ulong)v >> sc);
+ break;
+ }
+ }
+ return v;
+}
+
+void
+dpex(long inst, long o1, long o2, int rd)
+{
+ int cbit;
+
+ cbit = 0;
+ switch((inst>>21) & 0xf) {
+ case 0: /* and */
+ reg.r[rd] = o1 & o2;
+ cbit = 1;
+ break;
+ case 1: /* eor */
+ reg.r[rd] = o1 ^ o2;
+ cbit = 1;
+ break;
+ case 2: /* sub */
+ reg.r[rd] = o1 - o2;
+ case 10: /* cmp */
+ if(inst & Sbit) {
+ reg.cc1 = o1;
+ reg.cc2 = o2;
+ reg.compare_op = CCcmp;
+ }
+ return;
+ case 3: /* rsb */
+ reg.r[rd] = o2 - o1;
+ if(inst & Sbit) {
+ reg.cc1 = o2;
+ reg.cc2 = o1;
+ reg.compare_op = CCcmp;
+ }
+ return;
+ case 4: /* add */
+ if(calltree && rd == REGPC && o2 == 0) {
+ Symbol s;
+
+ findsym(o1 + o2, CTEXT, &s);
+ Bprint(bioout, "%8lux return to %lux %s r0=%lux\n",
+ reg.r[REGPC], o1 + o2, s.name, reg.r[REGRET]);
+ }
+ reg.r[rd] = o1 + o2;
+ if(inst & Sbit) {
+ if(((uvlong)(ulong)o1 + (uvlong)(ulong)o2) & (1LL << 32))
+ reg.cbit = 1;
+ else
+ reg.cbit = 0;
+ reg.cc1 = o2;
+ reg.cc2 = -o1;
+ reg.compare_op = CCcmp;
+ }
+ return;
+ case 5: /* adc */
+ case 6: /* sbc */
+ case 7: /* rsc */
+ undef(inst);
+ case 8: /* tst */
+ if(inst & Sbit) {
+ reg.cc1 = o1;
+ reg.cc2 = o2;
+ reg.compare_op = CCtst;
+ }
+ return;
+ case 9: /* teq */
+ if(inst & Sbit) {
+ reg.cc1 = o1;
+ reg.cc2 = o2;
+ reg.compare_op = CCteq;
+ }
+ return;
+ case 11: /* cmn */
+ if(inst & Sbit) {
+ reg.cc1 = o1;
+ reg.cc2 = -o2;
+ reg.compare_op = CCcmp;
+ }
+ return;
+ case 12: /* orr */
+ reg.r[rd] = o1 | o2;
+ cbit = 1;
+ break;
+ case 13: /* mov */
+ reg.r[rd] = o2;
+ cbit = 1;
+ break;
+ case 14: /* bic */
+ reg.r[rd] = o1 & ~o2;
+ cbit = 1;
+ break;
+ case 15: /* mvn */
+ reg.r[rd] = ~o2;
+ cbit = 1;
+ break;
+ }
+ if(inst & Sbit) {
+ if(cbit)
+ reg.cbit = reg.cout;
+ reg.cc1 = reg.r[rd];
+ reg.cc2 = 0;
+ reg.compare_op = CCcmp;
+ }
+}
+
+/*
+ * data processing instruction R,R,R
+ */
+void
+Idp0(ulong inst)
+{
+ int rn, rd, rm;
+ long o1, o2;
+
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+ rm = inst & 0xf;
+ o1 = reg.r[rn];
+ if(rn == REGPC)
+ o1 += 8;
+ o2 = reg.r[rm];
+ if(rm == REGPC)
+ o2 += 8;
+
+ dpex(inst, o1, o2, rd);
+ if(trace)
+ itrace("%s%s\tR%d,R%d,R%d =#%x",
+ reg.ip->name, cond[reg.cond],
+ rm, rn, rd,
+ reg.r[rd]);
+ if(rd == REGPC)
+ reg.r[rd] -= 4;
+}
+
+/*
+ * data processing instruction (R<>#),R,R
+ */
+void
+Idp1(ulong inst)
+{
+ int rn, rd, rm, st, sc;
+ long o1, o2;
+
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+ rm = inst & 0xf;
+ st = (inst>>5) & 0x3;
+ sc = (inst>>7) & 0x1f;
+ o1 = reg.r[rn];
+ if(rn == REGPC)
+ o1 += 8;
+ o2 = reg.r[rm];
+ if(rm == REGPC)
+ o2 += 8;
+ o2 = shift(o2, st, sc, 0);
+ dpex(inst, o1, o2, rd);
+ if(trace)
+ itrace("%s%s\tR%d%s%d,R%d,R%d =#%x",
+ reg.ip->name, cond[reg.cond], rm, shtype[st], sc, rn, rd,
+ reg.r[rd]);
+ if(rd == REGPC)
+ reg.r[rd] -= 4;
+}
+
+/*
+ * data processing instruction (R<>R),R,R
+ */
+void
+Idp2(ulong inst)
+{
+ int rn, rd, rm, rs, st;
+ long o1, o2, o3;
+
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+ rm = inst & 0xf;
+ st = (inst>>5) & 0x3;
+ rs = (inst>>8) & 0xf;
+ o1 = reg.r[rn];
+ if(rn == REGPC)
+ o1 += 8;
+ o2 = reg.r[rm];
+ if(rm == REGPC)
+ o2 += 8;
+ o3 = reg.r[rs];
+ if(rs == REGPC)
+ o3 += 8;
+ o2 = shift(o2, st, o3, 1);
+ dpex(inst, o1, o2, rd);
+ if(trace)
+ itrace("%s%s\tR%d%sR%d=%d,R%d,R%d =#%x",
+ reg.ip->name, cond[reg.cond], rm, shtype[st], rs, o3, rn, rd,
+ reg.r[rd]);
+ if(rd == REGPC)
+ reg.r[rd] -= 4;
+}
+
+/*
+ * data processing instruction #<>#,R,R
+ */
+void
+Idp3(ulong inst)
+{
+ int rn, rd, sc;
+ long o1, o2;
+
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+ o1 = reg.r[rn];
+ if(rn == REGPC)
+ o1 += 8;
+ o2 = inst & 0xff;
+ sc = (inst>>7) & 0x1e;
+ o2 = (o2 >> sc) | (o2 << (32 - sc));
+
+ dpex(inst, o1, o2, rd);
+ if(trace)
+ itrace("%s%s\t#%x,R%d,R%d =#%x",
+ reg.ip->name, cond[reg.cond], o2, rn, rd,
+ reg.r[rd]);
+ if(rd == REGPC)
+ reg.r[rd] -= 4;
+}
+
+void
+Imul(ulong inst)
+{
+ int rs, rd, rm;
+
+ rd = (inst>>16) & 0xf;
+ rs = (inst>>8) & 0xf;
+ rm = inst & 0xf;
+
+ if(rd == REGPC || rs == REGPC || rm == REGPC || rd == rm)
+ undef(inst);
+
+ reg.r[rd] = reg.r[rm]*reg.r[rs];
+
+ if(trace)
+ itrace("%s%s\tR%d,R%d,R%d =#%x",
+ reg.ip->name, cond[reg.cond], rs, rm, rd,
+ reg.r[rd]);
+}
+
+void
+Imull(ulong inst)
+{
+ vlong v;
+ int rs, rd, rm, rn;
+
+ rd = (inst>>16) & 0xf;
+ rn = (inst>>12) & 0xf;
+ rs = (inst>>8) & 0xf;
+ rm = inst & 0xf;
+
+ if(rd == REGPC || rn == REGPC || rs == REGPC || rm == REGPC
+ || rd == rm || rn == rm || rd == rn)
+ undef(inst);
+
+ if(inst & (1<<22)){
+ v = (vlong)reg.r[rm] * (vlong)reg.r[rs];
+ if(inst & (1 << 21))
+ v += reg.r[rn];
+ }else{
+ v = (uvlong)(ulong)reg.r[rm] * (uvlong)(ulong)reg.r[rs];
+ if(inst & (1 << 21))
+ v += (ulong)reg.r[rn];
+ }
+ reg.r[rd] = v >> 32;
+ reg.r[rn] = v;
+
+ if(trace)
+ itrace("%s%s\tR%d,R%d,(R%d,R%d) =#%llx",
+ reg.ip->name, cond[reg.cond], rs, rm, rn, rd,
+ v);
+}
+
+void
+Imula(ulong inst)
+{
+ int rs, rd, rm, rn;
+
+ rd = (inst>>16) & 0xf;
+ rn = (inst>>12) & 0xf;
+ rs = (inst>>8) & 0xf;
+ rm = inst & 0xf;
+
+ if(rd == REGPC || rn == REGPC || rs == REGPC || rm == REGPC || rd == rm)
+ undef(inst);
+
+ reg.r[rd] = reg.r[rm]*reg.r[rs] + reg.r[rn];
+
+ if(trace)
+ itrace("%s%s\tR%d,R%d,R%d,R%d =#%x",
+ reg.ip->name, cond[reg.cond], rs, rm, rn, rd,
+ reg.r[rd]);
+}
+
+void
+Iswap(ulong inst)
+{
+ int rn, rd, rm;
+ ulong address, value, bbit;
+
+ bbit = inst & (1<<22);
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+ rm = (inst>>0) & 0xf;
+
+ address = reg.r[rn];
+ if(bbit) {
+ value = getmem_b(address);
+ putmem_b(address, reg.r[rm]);
+ } else {
+ value = getmem_w(address);
+ putmem_w(address, reg.r[rm]);
+ }
+ reg.r[rd] = value;
+
+ if(trace) {
+ char *bw, *dotc;
+
+ bw = "";
+ if(bbit)
+ bw = "B";
+ dotc = cond[reg.cond];
+
+ itrace("SWP%s%s\t#%x(R%d),R%d #%lux=#%x",
+ bw, dotc,
+ rn, rd,
+ address, value);
+ }
+}
+
+/*
+ * load/store word/byte
+ */
+void
+Imem1(ulong inst)
+{
+ int rn, rd, off, rm, sc, st;
+ ulong address, value, pbit, ubit, bbit, wbit, lbit, bit25;
+
+ bit25 = inst & (1<<25);
+ pbit = inst & (1<<24);
+ ubit = inst & (1<<23);
+ bbit = inst & (1<<22);
+ wbit = inst & (1<<21);
+ lbit = inst & (1<<20);
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+
+ SET(st);
+ SET(sc);
+ SET(rm);
+ if(bit25) {
+ rm = inst & 0xf;
+ st = (inst>>5) & 0x3;
+ sc = (inst>>7) & 0x1f;
+ off = reg.r[rm];
+ if(rm == REGPC)
+ off += 8;
+ off = shift(off, st, sc, 0);
+ } else {
+ off = inst & 0xfff;
+ }
+ if(!ubit)
+ off = -off;
+ if(rn == REGPC)
+ off += 8;
+
+ address = reg.r[rn];
+ if(pbit)
+ address += off;
+
+ if(lbit) {
+ if(bbit)
+ value = getmem_b(address);
+ else
+ value = getmem_w(address);
+ if(rd == REGPC)
+ value -= 4;
+ reg.r[rd] = value;
+ } else {
+ value = reg.r[rd];
+ if(rd == REGPC)
+ value -= 4;
+ if(bbit)
+ putmem_b(address, value);
+ else
+ putmem_w(address, value);
+ }
+ if(!(pbit && !wbit))
+ reg.r[rn] += off;
+
+ if(trace) {
+ char *bw, *dotp, *dotc;
+
+ bw = "W";
+ if(bbit)
+ bw = "BU";
+ dotp = "";
+ if(!pbit)
+ dotp = ".P";
+ dotc = cond[reg.cond];
+
+ if(lbit) {
+ if(!bit25)
+ itrace("MOV%s%s%s\t#%x(R%d),R%d #%lux=#%x",
+ bw, dotp, dotc,
+ off, rn, rd,
+ address, value);
+ else
+ itrace("MOV%s%s%s\t(R%d%s%d)(R%d),R%d #%lux=#%x",
+ bw, dotp, dotc,
+ rm, shtype[st], sc, rn, rd,
+ address, value);
+ } else {
+ if(!bit25)
+ itrace("MOV%s%s%s\tR%d,#%x(R%d) #%lux=#%x",
+ bw, dotp, dotc,
+ rd, off, rn,
+ address, value);
+ else
+ itrace("MOV%s%s%s\tR%d,(R%d%s%d)(R%d) #%lux=#%x",
+ bw, dotp, dotc,
+ rd, rm, shtype[st], sc, rn,
+ address, value);
+ }
+ }
+}
+
+/*
+ * load/store unsigned byte/half word
+ */
+void
+Imem2(ulong inst)
+{
+ int rn, rd, off, rm;
+ ulong address, value, pbit, ubit, hbit, sbit, wbit, lbit, bit22;
+
+ pbit = inst & (1<<24);
+ ubit = inst & (1<<23);
+ bit22 = inst & (1<<22);
+ wbit = inst & (1<<21);
+ lbit = inst & (1<<20);
+ sbit = inst & (1<<6);
+ hbit = inst & (1<<5);
+ rn = (inst>>16) & 0xf;
+ rd = (inst>>12) & 0xf;
+
+ SET(rm);
+ if(bit22) {
+ off = ((inst>>4) & 0xf0) | (inst & 0xf);
+ } else {
+ rm = inst & 0xf;
+ off = reg.r[rm];
+ if(rm == REGPC)
+ off += 8;
+ }
+ if(!ubit)
+ off = -off;
+ if(rn == REGPC)
+ off += 8;
+
+ address = reg.r[rn];
+ if(pbit)
+ address += off;
+
+ if(lbit) {
+ if(hbit) {
+ value = getmem_h(address);
+ if(sbit && (value & 0x8000))
+ value |= 0xffff0000;
+ } else {
+ value = getmem_b(address);
+ if(value & 0x80)
+ value |= 0xffffff00;
+ }
+ if(rd == REGPC)
+ value -= 4;
+ reg.r[rd] = value;
+ } else {
+ value = reg.r[rd];
+ if(rd == REGPC)
+ value -= 4;
+ if(hbit) {
+ putmem_h(address, value);
+ } else {
+ putmem_b(address, value);
+ }
+ }
+ if(!(pbit && !wbit))
+ reg.r[rn] += off;
+
+ if(trace) {
+ char *hb, *dotp, *dotc;
+
+ hb = "B";
+ if(hbit)
+ hb = "H";
+ dotp = "";
+ if(!pbit)
+ dotp = ".P";
+ dotc = cond[reg.cond];
+
+ if(lbit) {
+ if(bit22)
+ itrace("MOV%s%s%s\t#%x(R%d),R%d #%lux=#%x",
+ hb, dotp, dotc,
+ off, rn, rd,
+ address, value);
+ else
+ itrace("MOV%s%s%s\t(R%d)(R%d),R%d #%lux=#%x",
+ hb, dotp, dotc,
+ rm, rn, rd,
+ address, value);
+ } else {
+ if(bit22)
+ itrace("MOV%s%s%s\tR%d,#%x(R%d) #%lux=#%x",
+ hb, dotp, dotc,
+ rd, off, rn,
+ address, value);
+ else
+ itrace("MOV%s%s%s\tR%d,(R%d)(R%d) #%lux=#%x",
+ hb, dotp, dotc,
+ rd, rm, rn,
+ address, value);
+ }
+ }
+}
+
+void
+Ilsm(ulong inst)
+{
+ char pbit, ubit, sbit, wbit, lbit;
+ int i, rn, reglist;
+ ulong address, predelta, postdelta;
+
+ pbit = (inst>>24) & 0x1;
+ ubit = (inst>>23) & 0x1;
+ sbit = (inst>>22) & 0x1;
+ wbit = (inst>>21) & 0x1;
+ lbit = (inst>>20) & 0x1;
+ rn = (inst>>16) & 0xf;
+ reglist = inst & 0xffff;
+
+ if(reglist & 0x8000)
+ undef(reg.ir);
+ if(sbit)
+ undef(reg.ir);
+
+ address = reg.r[rn];
+
+ if(pbit) {
+ predelta = 4;
+ postdelta = 0;
+ } else {
+ predelta = 0;
+ postdelta = 4;
+ }
+ if(ubit) {
+ for (i = 0; i < 16; ++i) {
+ if(!(reglist & (1 << i)))
+ continue;
+ address += predelta;
+ if(lbit)
+ reg.r[i] = getmem_w(address);
+ else
+ putmem_w(address, reg.r[i]);
+ address += postdelta;
+ }
+ } else {
+ for (i = 15; 0 <= i; --i) {
+ if(!(reglist & (1 << i)))
+ continue;
+ address -= predelta;
+ if(lbit)
+ reg.r[i] = getmem_w(address);
+ else
+ putmem_w(address, reg.r[i]);
+ address -= postdelta;
+ }
+ }
+ if(wbit) {
+ reg.r[rn] = address;
+ }
+
+ if(trace) {
+ itrace("%s.%c%c\tR%d=%lux%s, <%lux>",
+ (lbit ? "LDM" : "STM"), (ubit ? 'I' : 'D'), (pbit ? 'B' : 'A'),
+ rn, reg.r[rn], (wbit ? "!" : ""), reglist);
+ }
+}
+
+void
+Ib(ulong inst)
+{
+ long v;
+
+ v = inst & 0xffffff;
+ v = reg.r[REGPC] + 8 + ((v << 8) >> 6);
+ if(trace)
+ itrace("B%s\t#%lux", cond[reg.cond], v);
+ reg.r[REGPC] = v - 4;
+}
+
+void
+Ibl(ulong inst)
+{
+ long v;
+ Symbol s;
+
+ v = inst & 0xffffff;
+ v = reg.r[REGPC] + 8 + ((v << 8) >> 6);
+ if(trace)
+ itrace("BL%s\t#%lux", cond[reg.cond], v);
+
+ if(calltree) {
+ findsym(v, CTEXT, &s);
+ Bprint(bioout, "%8lux %s(", reg.r[REGPC], s.name);
+ printparams(&s, reg.r[13]);
+ Bprint(bioout, "from ");
+ printsource(reg.r[REGPC]);
+ Bputc(bioout, '\n');
+ }
+
+ reg.r[REGLINK] = reg.r[REGPC] + 4;
+ reg.r[REGPC] = v - 4;
+}
diff --git a/sys/src/cmd/5i/stats.c b/sys/src/cmd/5i/stats.c
new file mode 100755
index 000000000..65485533d
--- /dev/null
+++ b/sys/src/cmd/5i/stats.c
@@ -0,0 +1,199 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.h"
+
+#define Percent(num, max) ((max)?((num)*100)/(max):0)
+#define prof prof5i
+
+extern Inst itab[];
+Inst *tables[] = { itab, 0 };
+
+void
+isum(void)
+{
+ Inst *i;
+ int total, mems, arith, branch;
+ int useddelay, taken, syscall;
+ int pct, j;
+
+ total = 0;
+ mems = 0;
+ arith = 0;
+ branch = 0;
+ useddelay = 0;
+ taken = 0;
+ syscall = 0;
+
+ /* Compute the total so we can have percentages */
+ for(i = itab; 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) {
+ /* This is gross */
+ 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 Imem:
+ mems += i->count;
+ break;
+ case Iarith:
+ arith += i->count;
+ break;
+ case Ibranch:
+ branch += i->count;
+ taken += i->taken;
+ useddelay += i->useddelay;
+ break;
+ case Isyscall:
+ syscall += i->count;
+ break;
+ }
+
+ }
+ }
+ }
+
+ Bprint(bioout, "\n%-8ud Memory cycles\n", mems+total);
+ Bprint(bioout, "%-8ud %3d%% Instruction cycles\n",
+ total, Percent(total, mems+total));
+ Bprint(bioout, "%-8ud %3d%% Data cycles\n\n",
+ mems, Percent(mems, mems+total));
+
+ Bprint(bioout, "%-8ud %3d%% Arithmetic\n",
+ arith, Percent(arith, 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/5i/symbols.c b/sys/src/cmd/5i/symbols.c
new file mode 100755
index 000000000..9accb9d1e
--- /dev/null
+++ b/sys/src/cmd/5i/symbols.c
@@ -0,0 +1,95 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "arm.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.r[15];
+ sp = reg.r[13];
+ 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[14];
+ 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/5i/syscall.c b/sys/src/cmd/5i/syscall.c
new file mode 100755
index 000000000..b6402bfd5
--- /dev/null
+++ b/sys/src/cmd/5i/syscall.c
@@ -0,0 +1,807 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define EXTERN
+#include "arm.h"
+
+#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] "Running",
+ [_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[1]]);
+ exits(0);
+}
+
+void
+sys_errstr(void)
+{
+ ulong str;
+
+ str = getmem_w(reg.r[13]+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;
+ int n;
+
+ str = getmem_w(reg.r[13]+4);
+ n = getmem_w(reg.r[13]+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
+sysbind(void)
+{
+ ulong pname, pold, flags;
+ char name[1024], old[1024];
+ int n;
+
+ pname = getmem_w(reg.r[13]+4);
+ pold = getmem_w(reg.r[13]+8);
+ flags = getmem_w(reg.r[13]+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
+sysfd2path(void)
+{
+ int n;
+ uint fd;
+ ulong str;
+ char buf[1024];
+
+ fd = getmem_w(reg.r[13]+4);
+ str = getmem_w(reg.r[13]+8);
+ n = getmem_w(reg.r[13]+12);
+ if(sysdbg)
+ itrace("fd2path(0x%lux, 0x%lux, 0x%lux)", fd, str, n);
+ reg.r[1] = -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
+syschdir(void)
+{
+ char file[1024];
+ int n;
+ ulong name;
+
+ name = getmem_w(reg.r[13]+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[13]+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[13]+4);
+ newfd = getmem_w(reg.r[13]+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[13]+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[13]+4);
+ mode = getmem_w(reg.r[13]+8);
+ memio(file, name, sizeof(file), MemReadstring);
+
+ n = open(file, mode);
+ if(n < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ if(sysdbg)
+ itrace("open(0x%lux='%s', 0x%lux) = %d", name, file, mode, n);
+
+ 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[13]+4);
+ a = getmem_w(reg.r[13]+8);
+ size = getmem_w(reg.r[13]+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)
+{
+ sysread(getmem_v(reg.r[13]+16));
+}
+
+void
+sysseek(void)
+{
+ int fd;
+ ulong mode;
+ ulong retp;
+ vlong v;
+
+ retp = getmem_w(reg.r[13]+4);
+ fd = getmem_w(reg.r[13]+8);
+ v = getmem_v(reg.r[13]+16);
+ mode = getmem_w(reg.r[13]+20);
+ if(sysdbg)
+ itrace("seek(%d, %lld, %d)", fd, v, mode);
+
+ v = seek(fd, v, mode);
+ if(v < 0)
+ errstr(errbuf, sizeof errbuf);
+
+ putmem_v(retp, v);
+}
+
+void
+sysoseek(void)
+{
+ int fd, n;
+ ulong off, mode;
+
+ fd = getmem_w(reg.r[13]+4);
+ off = getmem_w(reg.r[13]+8);
+ mode = getmem_w(reg.r[13]+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
+syssleep(void)
+{
+ ulong len;
+ int n;
+
+ len = getmem_w(reg.r[13]+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[13]+4);
+ edir = getmem_w(reg.r[13]+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[13]+4);
+ edir = getmem_w(reg.r[13]+8);
+ n = getmem_w(reg.r[13]+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];
+ extern int _fstat(int, char*); /* old system call */
+ ulong edir;
+ int n, fd;
+
+ fd = getmem_w(reg.r[13]+4);
+ edir = getmem_w(reg.r[13]+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[13]+4);
+ edir = getmem_w(reg.r[13]+8);
+ n = getmem_w(reg.r[13]+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[13]+4);
+ a = getmem_w(reg.r[13]+8);
+ size = getmem_w(reg.r[13]+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, 0x%llx) = %d", fd, a, size, offset, n);
+
+ free(buf);
+
+ reg.r[REGRET] = n;
+}
+
+void
+sys_write(void)
+{
+ syswrite(-1LL);
+}
+
+void
+syspwrite(void)
+{
+ syswrite(getmem_v(reg.r[13]+16));
+}
+
+void
+syspipe(void)
+{
+ int n, p[2];
+ ulong fd;
+
+ fd = getmem_w(reg.r[13]+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[13]+4);
+ mode = getmem_w(reg.r[13]+8);
+ perm = getmem_w(reg.r[13]+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[13]+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[13]+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[13]+4);
+ if(sysdbg)
+ itrace("notify(0x%lux)\n", nofunc);
+
+ reg.r[REGRET] = 0;
+}
+
+void
+sys_wait(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysawait(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysrfork(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+syswstat(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sys_wstat(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysfwstat(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sys_fwstat(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysnoted(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+syssegattach(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+syssegdetach(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+syssegfree(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+syssegflush(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysrendezvous(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysunmount(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysfork(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysforkpgrp(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+syssegbrk(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysmount(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysalarm(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysexec(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sys_fsession(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysfauth(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ exits(0);
+}
+void
+sysfversion(void)
+{
+ Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGARG]]);
+ 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
+Ssyscall(ulong)
+{
+ int call;
+
+ call = reg.r[REGARG];
+ if(call < 0 || call >= nelem(systab) || systab[call] == nil) {
+ Bprint(bioout, "bad system call %d (%#ux)\n", call, call);
+ dumpreg();
+ Bflush(bioout);
+ return;
+ }
+
+ if(trace)
+ itrace("SWI\t%s", sysctab[call]);
+ (*systab[call])();
+ Bflush(bioout);
+}