summaryrefslogtreecommitdiff
path: root/libinterp
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libinterp
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libinterp')
-rw-r--r--libinterp/NOTICE17
-rw-r--r--libinterp/README1
-rw-r--r--libinterp/alt.c297
-rw-r--r--libinterp/comp-386.c1975
-rw-r--r--libinterp/comp-68020.c2074
-rw-r--r--libinterp/comp-arm.c2260
-rw-r--r--libinterp/comp-mips.c1955
-rw-r--r--libinterp/comp-power.c2257
-rw-r--r--libinterp/comp-s800.c2024
-rw-r--r--libinterp/comp-sparc.c1882
-rw-r--r--libinterp/comp-spim.c1
-rw-r--r--libinterp/comp-thumb.c2466
-rw-r--r--libinterp/conv.c110
-rw-r--r--libinterp/das-386.c1630
-rw-r--r--libinterp/das-68000.c1
-rw-r--r--libinterp/das-68020.c1940
-rw-r--r--libinterp/das-arm.c535
-rw-r--r--libinterp/das-mips.c531
-rw-r--r--libinterp/das-power.c961
-rw-r--r--libinterp/das-s800.c457
-rw-r--r--libinterp/das-sparc.c833
-rw-r--r--libinterp/das-spim.c1
-rw-r--r--libinterp/das-stub.c9
-rw-r--r--libinterp/das-thumb.c548
-rw-r--r--libinterp/dec.c1811
-rw-r--r--libinterp/decgen.c122
-rw-r--r--libinterp/dlm-Inferno.c101
-rw-r--r--libinterp/dlm-Nt.c48
-rw-r--r--libinterp/dlm-Plan9.c101
-rw-r--r--libinterp/dlm-Posix.c48
-rw-r--r--libinterp/draw.c2345
-rw-r--r--libinterp/drawmod.h94
-rw-r--r--libinterp/freetype.c231
-rw-r--r--libinterp/freetypemod.h11
-rw-r--r--libinterp/gc.c383
-rw-r--r--libinterp/geom.c309
-rw-r--r--libinterp/heap.c499
-rw-r--r--libinterp/heapaudit.c198
-rw-r--r--libinterp/ipint.c547
-rw-r--r--libinterp/keyring.c2511
-rw-r--r--libinterp/keyring.h75
-rw-r--r--libinterp/link.c132
-rw-r--r--libinterp/load.c638
-rw-r--r--libinterp/loader.c444
-rw-r--r--libinterp/loadermod.h13
-rw-r--r--libinterp/math.c955
-rw-r--r--libinterp/mathmod.h73
-rw-r--r--libinterp/mkfile120
-rw-r--r--libinterp/mkoptab19
-rw-r--r--libinterp/optab.h179
-rw-r--r--libinterp/prefab.c824
-rw-r--r--libinterp/raise.c25
-rw-r--r--libinterp/readmod.c84
-rw-r--r--libinterp/runt.c496
-rw-r--r--libinterp/runt.h3919
-rw-r--r--libinterp/sign.c29
-rw-r--r--libinterp/stack.c118
-rw-r--r--libinterp/string.c612
-rw-r--r--libinterp/sysmod.h47
-rw-r--r--libinterp/tab.h184
-rw-r--r--libinterp/tk.c1295
-rw-r--r--libinterp/tkmod.h15
-rw-r--r--libinterp/validstk.c53
-rw-r--r--libinterp/xec.c1692
64 files changed, 46165 insertions, 0 deletions
diff --git a/libinterp/NOTICE b/libinterp/NOTICE
new file mode 100644
index 00000000..7a10f1ba
--- /dev/null
+++ b/libinterp/NOTICE
@@ -0,0 +1,17 @@
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2006 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
diff --git a/libinterp/README b/libinterp/README
new file mode 100644
index 00000000..3e346faf
--- /dev/null
+++ b/libinterp/README
@@ -0,0 +1 @@
+comp-68020.c has not been tested recently
diff --git a/libinterp/alt.c b/libinterp/alt.c
new file mode 100644
index 00000000..61bda2e3
--- /dev/null
+++ b/libinterp/alt.c
@@ -0,0 +1,297 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define OP(fn) void fn(void)
+#define W(p) *((WORD*)(p))
+
+#define CANGET(c) ((c)->size > 0)
+#define CANPUT(c) ((c)->buf != H && (c)->size < (c)->buf->len)
+
+extern OP(isend);
+extern OP(irecv);
+
+/*
+ * Count the number of ready channels in an array of channels
+ * Set each channel's alt pointer to the owning prog
+ */
+static int
+altmark(Channel *c, Prog *p)
+{
+ int nrdy;
+ Array *a;
+ Channel **ca, **ec;
+
+ nrdy = 0;
+ a = (Array*)c;
+ ca = (Channel**)a->data;
+ ec = ca + a->len;
+ while(ca < ec) {
+ c = *ca;
+ if(c != H) {
+ if(c->send->prog || CANGET(c))
+ nrdy++;
+ cqadd(&c->recv, p);
+ }
+ ca++;
+ }
+
+ return nrdy;
+}
+
+/*
+ * Remove alt references to an array of channels
+ */
+static void
+altunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn)
+{
+ int n;
+ Array *a;
+ Channel **ca, **ec;
+
+ n = 0;
+ a = (Array*)c;
+ ca = (Channel**)a->data;
+ ec = ca + a->len;
+ while(ca < ec) {
+ c = *ca;
+ if(c != H && c->recv->prog)
+ cqdelp(&c->recv, p);
+ if(sr == 1 && *sel == c) {
+ W(p->R.d) = dn;
+ p->ptr = ptr + 1;
+ ptr[0] = n;
+ *sel = nil;
+ }
+ ca++;
+ n++;
+ }
+}
+
+/*
+ * ALT Pass 1 - Count the number of ready channels and mark
+ * each channel as ALT by this prog
+ */
+static int
+altrdy(Alt *a, Prog *p)
+{
+ char *e;
+ Type *t;
+ int nrdy;
+ Channel *c;
+ Altc *ac, *eac;
+
+ e = nil;
+ nrdy = 0;
+
+ ac = a->ac + a->nsend;
+ eac = ac + a->nrecv;
+ while(ac < eac) {
+ c = ac->c;
+ ac++;
+ if(c == H) {
+ e = exNilref;
+ continue;
+ }
+ t = D2H(c)->t;
+ if(t == &Tarray)
+ nrdy += altmark(c, p);
+ else {
+ if(c->send->prog || CANGET(c))
+ nrdy++;
+ cqadd(&c->recv, p);
+ }
+ }
+
+ ac = a->ac;
+ eac = ac + a->nsend;
+ while(ac < eac) {
+ c = ac->c;
+ ac++;
+ if(c == H) {
+ e = exNilref;
+ continue;
+ }
+ if(c->recv->prog || CANPUT(c)) {
+ if(c->recv->prog == p) {
+ e = exAlt;
+ continue;
+ }
+ nrdy++;
+ }
+ cqadd(&c->send, p);
+ }
+
+ if(e != nil) {
+ altdone(a, p, nil, -1);
+ error(e);
+ }
+
+ return nrdy;
+}
+
+/*
+ * ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item
+ */
+void
+altdone(Alt *a, Prog *p, Channel *sel, int sr)
+{
+ int n;
+ Type *t;
+ Channel *c;
+ Altc *ac, *eac;
+
+ n = 0;
+ ac = a->ac;
+ eac = a->ac + a->nsend;
+ while(ac < eac) {
+ c = ac->c;
+ if(c != H) {
+ if(c->send->prog)
+ cqdelp(&c->send, p);
+ if(sr == 0 && c == sel) {
+ p->ptr = ac->ptr;
+ W(p->R.d) = n;
+ sel = nil;
+ }
+ }
+ ac++;
+ n++;
+ }
+
+ eac = a->ac + a->nsend + a->nrecv;
+ while(ac < eac) {
+ c = ac->c;
+ if(c != H) {
+ t = D2H(c)->t;
+ if(t == &Tarray)
+ altunmark(c, ac->ptr, p, sr, &sel, n);
+ else {
+ if(c->recv->prog)
+ cqdelp(&c->recv, p);
+ if(sr == 1 && c == sel) {
+ p->ptr = ac->ptr;
+ W(p->R.d) = n;
+ sel = nil;
+ }
+ }
+ }
+ ac++;
+ n++;
+ }
+}
+
+/*
+ * ALT Pass 2 - Perform the communication on the chosen channel
+ */
+static void
+altcomm(Alt *a, int which)
+{
+ Type *t;
+ Array *r;
+ int n, an;
+ WORD *ptr;
+ Altc *ac, *eac;
+ Channel *c, **ca, **ec;
+
+ n = 0;
+ ac = a->ac;
+ eac = ac + a->nsend;
+ while(ac < eac) {
+ c = ac->c;
+ if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) {
+ W(R.d) = n;
+ R.s = ac->ptr;
+ R.d = &c;
+ isend();
+ return;
+ }
+ ac++;
+ n++;
+ }
+
+ eac = eac + a->nrecv;
+ while(ac < eac) {
+ c = ac->c;
+ t = D2H(c)->t;
+ if(t == &Tarray) {
+ an = 0;
+ r = (Array*)c;
+ ca = (Channel**)r->data;
+ ec = ca + r->len;
+ while(ca < ec) {
+ c = *ca;
+ if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) {
+ W(R.d) = n;
+ R.s = &c;
+ ptr = ac->ptr;
+ R.d = ptr + 1;
+ ptr[0] = an;
+ irecv();
+ return;
+ }
+ ca++;
+ an++;
+ }
+ }
+ else
+ if((c->send->prog != nil || CANGET(c)) && which-- == 0) {
+ W(R.d) = n;
+ R.s = &c;
+ R.d = ac->ptr;
+ irecv();
+ return;
+ }
+ ac++;
+ n++;
+ }
+ return;
+}
+
+void
+altgone(Prog *p)
+{
+ Alt *a;
+
+ if (p->state == Palt) {
+ a = p->R.s;
+ altdone(a, p, nil, -1);
+ p->kill = "alt channel hungup";
+ addrun(p);
+ }
+}
+
+void
+xecalt(int block)
+{
+ Alt *a;
+ Prog *p;
+ int nrdy;
+ static int xrand = -1;
+
+ p = currun();
+
+ a = R.s;
+ nrdy = altrdy(a, p);
+ if(nrdy == 0) {
+ if(block) {
+ delrun(Palt);
+ p->R.s = R.s;
+ p->R.d = R.d;
+ R.IC = 1;
+ R.t = 1;
+ return;
+ }
+ W(R.d) = a->nsend + a->nrecv;
+ altdone(a, p, nil, -1);
+ return;
+ }
+
+ xrand += xrand;
+ if(xrand < 0)
+ xrand ^= 0x88888EEF;
+
+ altcomm(a, xrand%nrdy);
+ altdone(a, p, nil, -1);
+}
diff --git a/libinterp/comp-386.c b/libinterp/comp-386.c
new file mode 100644
index 00000000..4f5d89c4
--- /dev/null
+++ b/libinterp/comp-386.c
@@ -0,0 +1,1975 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define DOT ((ulong)code)
+
+#define RESCHED 1 /* check for interpreter reschedule */
+
+enum
+{
+ RAX = 0,
+ RAH = 4,
+ RCX = 1,
+ RDX = 2,
+ RBX = 3,
+ RSP = 4,
+ RBP = 5,
+ RSI = 6,
+ RDI = 7,
+
+ RFP = RSI,
+ RMP = RDI,
+ RTA = RDX,
+ RTMP = RBX,
+
+ Omovzxb = 0xb6,
+ Omovzxw = 0xb7,
+ Osal = 0xd1,
+ Oaddf = 0xdc,
+ Ocall = 0xe8,
+ Ocallrm = 0xff,
+ Ocdq = 0x99,
+ Ocld = 0xfc,
+ Ocmpb = 0x38,
+ Ocmpw = 0x39,
+ Ocmpi = 0x83,
+ Odecrm = 0xff,
+ Oincr = 0x40,
+ Oincrm = 0xff,
+ Ojccl = 0x83,
+ Ojcsl = 0x82,
+ Ojeqb = 0x74,
+ Ojeql = 0x84,
+ Ojgel = 0x8d,
+ Ojgtl = 0x8f,
+ Ojhil = 0x87,
+ Ojlel = 0x8e,
+ Ojlsl = 0x86,
+ Ojltl = 0x8c,
+ Ojol = 0x80,
+ Ojnol = 0x81,
+ Ojbl = 0x82,
+ Ojael = 0x83,
+ Ojal = 0x87,
+ Ojnel = 0x85,
+ Ojbel = 0x86,
+ Ojneb = 0x75,
+ Ojgtb = 0x7f,
+ Ojgeb = 0x7d,
+ Ojleb = 0x7e,
+ Ojltb = 0x7c,
+ Ojmp = 0xe9,
+ Ojmpb = 0xeb,
+ Ojmprm = 0xff,
+ Oldb = 0x8a,
+ Olds = 0x89,
+ Oldw = 0x8b,
+ Olea = 0x8d,
+ Otestib = 0xf6,
+ Oshld = 0xa5,
+ Oshrd = 0xad,
+ Osar = 0xd3,
+ Osarimm = 0xc1,
+ Omov = 0xc7,
+ Omovf = 0xdd,
+ Omovimm = 0xb8,
+ Omovsb = 0xa4,
+ Orep = 0xf3,
+ Oret = 0xc3,
+ Oshl = 0xd3,
+ Oshr = 0xd1,
+ Ostb = 0x88,
+ Ostw = 0x89,
+ Osubf = 0xdc,
+ Oxchg = 0x87,
+ OxchgAX = 0x90,
+ Oxor = 0x31,
+ Opopl = 0x58,
+ Opushl = 0x50,
+ Opushrm = 0xff,
+ Oneg = 0xf7,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ MacRELQ = 7,
+ NMACRO
+};
+
+static uchar* code;
+static uchar* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static void macrelq(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(uchar*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+} mactab[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacFRAM, macfram, /* frame instruction */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+static void
+bounds(void)
+{
+ error(exBounds);
+}
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static int
+bc(int o)
+{
+ if(o < 127 && o > -128)
+ return 1;
+ return 0;
+}
+
+static void
+urk(void)
+{
+ error(exCompile);
+}
+
+static void
+genb(uchar o)
+{
+ *code++ = o;
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+ code[0] = o1;
+ code[1] = o2;
+ code += 2;
+}
+
+static void
+genw(ulong o)
+{
+ *(ulong*)code = o;
+ code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+ *code++ = inst;
+ if(disp == 0) {
+ *code++ = (0<<6)|(r<<3)|rm;
+ return;
+ }
+ if(bc(disp)) {
+ code[0] = (1<<6)|(r<<3)|rm;
+ code[1] = disp;
+ code += 2;
+ return;
+ }
+ *code++ = (2<<6)|(r<<3)|rm;
+ *(ulong*)code = disp;
+ code += 4;
+}
+
+static void
+con(ulong o, int r)
+{
+ if(o == 0) {
+ gen2(Oxor, (3<<6)|(r<<3)|r);
+ return;
+ }
+ genb(Omovimm+r);
+ genw(o);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ modrm(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ modrm(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ con(i->s.imm, r);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->s.i.f, ir, rta);
+ modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(i->d.imm, r);
+ return;
+ case DST(AFP):
+ modrm(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ modrm(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->d.i.f, ir, rta);
+ modrm(mi, i->d.i.s, rta, r);
+}
+
+static void
+bra(ulong dst, int op)
+{
+ dst -= (DOT+5);
+ genb(op);
+ genw(dst);
+}
+
+static void
+rbra(ulong dst, int op)
+{
+ dst += (ulong)base;
+ dst -= DOT+5;
+ genb(op);
+ genw(dst);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ genb(Omovimm+RAX);
+ genw((ulong)litpool);
+ modrm(Ostw, roff, RTMP, RAX);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ con((ulong)&R, RTMP);
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, RAX);
+ modrm(Ostw, O(REG, s), RTMP, RAX);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Olea, 0);
+ modrm(Ostw, O(REG, d), RTMP, RAX);
+ }
+ if(m & WRTPC) {
+ modrm(Omov, O(REG, PC), RTMP, 0);
+ pc = patch[i-mod->prog+1];
+ genw((ulong)base + pc);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal((ulong)base+pc, O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ modrm(Oldw, O(REG, d), RTMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ modrm(Olea, i->reg, RFP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ case AXINM:
+ modrm(Olea, i->reg, RMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ }
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+
+ bra((ulong)fn, Ocall);
+
+ con((ulong)&R, RTMP);
+ if(m & TCHECK) {
+ modrm(Ocmpi, O(REG, t), RTMP, 7);// CMPL $0, R.t
+ genb(0x00);
+ gen2(Ojeqb, 0x06); // JEQ .+6
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ }
+
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+
+ if(m & NEWPC) {
+ modrm(Oldw, O(REG, PC), RTMP, RAX);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+ }
+}
+
+static void
+mid(Inst *i, uchar mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ modrm(mi, i->reg, ir, r);
+}
+
+static void
+arith(Inst *i, int op2, int rm)
+{
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostw, 0);
+ return;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, op2, 0);
+ return;
+ }
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ if(bc(i->s.imm)) {
+ gen2(0x83, (3<<6)|(rm<<3)|RAX);
+ genb(i->s.imm);
+ }
+ else {
+ gen2(0x81, (3<<6)|(rm<<3)|RAX);
+ genw(i->s.imm);
+ }
+ opwst(i, Ostw, RAX);
+ return;
+ }
+ if(bc(i->s.imm)) {
+ opwst(i, 0x83, rm);
+ genb(i->s.imm);
+ return;
+ }
+ opwst(i, 0x81, rm);
+ genw(i->s.imm);
+}
+
+static void
+arithb(Inst *i, int op2)
+{
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ if(i->add&ARM) {
+ mid(i, Oldb, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostb, 0);
+ return;
+ }
+ opwld(i, Oldb, RAX);
+ opwst(i, op2, RAX);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op, int r)
+{
+ mid(i, ld, RAX);
+ opwld(i, Oldw, RCX);
+ gen2(op, (3<<6)|(r<<3)|RAX);
+ opwst(i, st, RAX);
+}
+
+static void
+arithf(Inst *i, int op)
+{
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, op);
+ opwst(i, Omovf, 3);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+ if(bc(v)) {
+ gen2(0x83, (3<<6)|(7<<3)|r);
+ genb(v);
+ return;
+ }
+ gen2(0x81, (3<<6)|(7<<3)|r);
+ genw(v);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Ojgel:
+ return Ojlel;
+ case Ojlel:
+ return Ojgel;
+ case Ojgtl:
+ return Ojltl;
+ case Ojltl:
+ return Ojgtl;
+ }
+ return b;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ if(RESCHED && i->d.ins <= i){
+ con((ulong)&R, RTMP);
+ /* sub $1, R.IC */
+ modrm(0x83, O(REG, IC), RTMP, 5);
+ genb(1);
+ gen2(Ojgtb, 5);
+ rbra(macro[MacRELQ], Ocall);
+ }
+}
+
+static void
+cbra(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldw, RAX);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ cmpl(RAX, i->s.imm);
+ jmp = swapbraop(jmp);
+ }
+ else
+ opwld(i, Ocmpw, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst;
+ uchar *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ocmpw, 4, RTMP, RAX);
+ label = 0;
+ dst = patch[i->d.ins-mod->prog];
+ switch(mode) {
+ case ANDAND:
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ case OROR:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ break;
+ case EQAND:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ }
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ocmpw, 0, RTMP, RAX);
+ genb(0x0f);
+ rbra(dst, jlsw);
+ if(label != nil)
+ *label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldb, RAX);
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ opwld(i, Ocmpb, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbraf(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, 3); // FCOMP
+ genb(0x9b); // FWAIT
+ gen2(0xdf, 0xe0); // FSTSW AX
+ genb(0x9e); // SAHF
+
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RAX); // v
+ genb(Opushl+RSI);
+ opwst(i, Olea, RSI); // table
+ rbra(macro[MacCASE], Ojmp);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)base + patch[t[2]];
+ t += 3;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ uchar *punt, *mlnil;
+
+ opwld(i, Oldw, RAX);
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM) {
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA);
+ } else {
+ gen2(Oldw, (3<<6)|(RTMP<<3)|RAX); // MOVL AX, RTMP
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (AX)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RAX); // assumes sizeof(Modl) == 8 hence 3
+ o = OA(Modlink, links)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA); // frame
+ genb(OxchgAX+RTMP); // get old AX back
+ }
+ modrm(0x83, O(Type, initialize), RTA, 7);
+ genb(0);
+ gen2(Ojneb, 0);
+ punt = code - 1;
+ genb(OxchgAX+RTA);
+ opwst(i, Olea, RTA);
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMFRA], Ocall);
+ rbra(patch[i-mod->prog+1], Ojmp);
+
+ *punt = code-punt-1;
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+}
+
+static void
+commcall(Inst *i)
+{
+ uchar *mlnil;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ opwld(i, Oldw, RCX);
+ modrm(Omov, O(Frame, lr), RCX, 0); // MOVL $.+1, lr(CX) f->lr = R.PC
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RCX, RFP); // MOVL RFP, fp(CX) f->fp = R.FP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Ostw, O(Frame, mr), RCX, RTA); // MOVL RTA, mr(CX) f->mr = R.M
+ opwst(i, Oldw, RTA); // MOVL ml, RTA
+ cmpl(RTA, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM)
+ modrm(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RTA, RAX);
+ else {
+ genb(Opushl+RCX);
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (RTA)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RTA); // assumes sizeof(Modl) == 8 hence 3
+ modrm(Oldw, OA(Modlink, links)+O(Modl, u.pc), RAX, RAX);
+ genb(Opopl+RCX);
+ }
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMCAL], Ocall);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 0, RTA, RAX); // MOVL 0(RTA), AX
+ modrm(op, 0, RTMP, RAX); // ADDL 0(RTMP), AX
+ modrm(Oldw, 4, RTA, RCX); // MOVL 4(RTA), CX
+ modrm(opc, 4, RTMP, RCX); // ADCL 4(RTMP), CX
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RCX);
+}
+
+static void
+shll(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshld, (3<<6)|(RAX<<3)|RBX);
+ gen2(Oshl, (3<<6)|(4<<3)|RAX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 0, RTA, RBX);
+ con(0, RAX);
+ gen2(Oshl, (3<<6)|(4<<3)|RBX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static void
+shrl(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshrd, (3<<6)|(RBX<<3)|RAX);
+ gen2(Osar, (3<<6)|(7<<3)|RBX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 4, RTA, RBX);
+ gen2(Oldw, (3<<6)|(RAX<<3)|RBX);
+ gen2(Osarimm, (3<<6)|(7<<3)|RBX);
+ genb(0x1f);
+ gen2(Osar, (3<<6)|(7<<3)|RAX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int r;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADL:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Oldb, RAX);
+ genb(0x0f);
+ gen2(0xb6, (3<<6)|(RAX<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ICVTFW:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdb, 3);
+ break;
+ case ICVTWF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdb, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTLF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdf, 5);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTFL:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdf, 7);
+ break;
+ case IHEADM:
+ opwld(i, Oldw, RAX);
+ modrm(Olea, OA(List, data), RAX, RAX);
+ goto movm;
+ case IMOVM:
+ opwld(i, Olea, RAX);
+ movm:
+ opwst(i, Olea, RBX);
+ mid(i, Oldw, RCX);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ genb(Ocld);
+ gen2(Orep, Omovsb);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ break;
+ case IRET:
+ rbra(macro[MacRET], Ojmp);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RTA);
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+ break;
+ case ILEA:
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ gen2(Ojmpb, 4);
+ genw(i->s.imm);
+ con((ulong)(code-4), RAX);
+ }
+ else
+ opwld(i, Olea, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADW:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, OA(List, data), RAX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADF:
+ opwld(i, Oldw, RAX);
+ modrm(Omovf, OA(List, data), RAX, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case IHEADB:
+ opwld(i, Oldw, RAX);
+ modrm(Oldb, OA(List, data), RAX, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, O(List, tail), RAX, RBX);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RBX);
+ if(i->op == IHEADP)
+ modrm(Oldw, OA(List, data), RBX, RBX);
+ movp:
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ rbra(macro[MacCOLR], Ocall);
+ opwst(i, Oldw, RAX);
+ opwst(i, Ostw, RBX);
+ rbra(macro[MacFRP], Ocall);
+ break;
+ case ILENA:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x02);
+ modrm(Oldw, O(Array, len), RBX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENC:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x09);
+ modrm(Oldw, O(String, len), RBX, RAX);
+ cmpl(RAX, 0);
+ gen2(Ojgeb, 0x02);
+ gen2(Oneg, (3<<6)|(3<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENL:
+ con(0, RAX);
+ opwld(i, Oldw, RBX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ modrm(Oldw, O(List, tail), RBX, RBX);
+ genb(Oincr+RAX);
+ gen2(Ojmpb, 0xf6);
+ opwst(i, Ostw, RAX);
+ break;
+ case IBEQF:
+ cbraf(i, Ojeql);
+ break;
+ case IBNEF:
+ cbraf(i, Ojnel);
+ break;
+ case IBLEF:
+ cbraf(i, Ojlsl);
+ break;
+ case IBLTF:
+ cbraf(i, Ojcsl);
+ break;
+ case IBGEF:
+ cbraf(i, Ojccl);
+ break;
+ case IBGTF:
+ cbraf(i, Ojhil);
+ break;
+ case IBEQW:
+ cbra(i, Ojeql);
+ break;
+ case IBLEW:
+ cbra(i, Ojlel);
+ break;
+ case IBNEW:
+ cbra(i, Ojnel);
+ break;
+ case IBGTW:
+ cbra(i, Ojgtl);
+ break;
+ case IBLTW:
+ cbra(i, Ojltl);
+ break;
+ case IBGEW:
+ cbra(i, Ojgel);
+ break;
+ case IBEQB:
+ cbrab(i, Ojeql);
+ break;
+ case IBLEB:
+ cbrab(i, Ojlsl);
+ break;
+ case IBNEB:
+ cbrab(i, Ojnel);
+ break;
+ case IBGTB:
+ cbrab(i, Ojhil);
+ break;
+ case IBLTB:
+ cbrab(i, Ojbl);
+ break;
+ case IBGEB:
+ cbrab(i, Ojael);
+ break;
+ case ISUBW:
+ arith(i, 0x29, 5);
+ break;
+ case ISUBB:
+ arithb(i, 0x28);
+ break;
+ case ISUBF:
+ arithf(i, 5);
+ break;
+ case IADDW:
+ arith(i, 0x01, 0);
+ break;
+ case IADDB:
+ arithb(i, 0x00);
+ break;
+ case IADDF:
+ arithf(i, 0);
+ break;
+ case IORW:
+ arith(i, 0x09, 1);
+ break;
+ case IORB:
+ arithb(i, 0x08);
+ break;
+ case IANDW:
+ arith(i, 0x21, 4);
+ break;
+ case IANDB:
+ arithb(i, 0x20);
+ break;
+ case IXORW:
+ arith(i, Oxor, 6);
+ break;
+ case IXORB:
+ arithb(i, 0x30);
+ break;
+ case ISHLW:
+ shift(i, Oldw, Ostw, 0xd3, 4);
+ break;
+ case ISHLB:
+ shift(i, Oldb, Ostb, 0xd2, 4);
+ break;
+ case ISHRW:
+ shift(i, Oldw, Ostw, 0xd3, 7);
+ break;
+ case ISHRB:
+ shift(i, Oldb, Ostb, 0xd2, 5);
+ break;
+ case IMOVF:
+ opwld(i, Omovf, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case INEGF:
+ opwld(i, Omovf, 0);
+ genb(0xd9);
+ genb(0xe0);
+ opwst(i, Omovf, 3);
+ break;
+ case IMOVB:
+ opwld(i, Oldb, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case IMOVW:
+ case ICVTLW: // Little endian
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ opwst(i, Omov, RAX);
+ genw(i->s.imm);
+ break;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWL:
+ opwst(i, Olea, RTMP);
+ opwld(i, Oldw, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ genb(0x99);
+ modrm(Ostw, 4, RTMP, RDX);
+ break;
+ case ICALL:
+ if(UXDST(i->add) != DST(AIMM))
+ opwst(i, Oldw, RTA);
+ opwld(i, Oldw, RAX);
+ modrm(Omov, O(Frame, lr), RAX, 0); // MOVL $.+1, lr(AX)
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RAX, RFP); // MOVL RFP, fp(AX)
+ gen2(Oldw, (3<<6)|(RFP<<3)|RAX); // MOVL AX,RFP
+ if(UXDST(i->add) != DST(AIMM)){
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA);
+ break;
+ }
+ /* no break */
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ rbra(patch[i->d.ins-mod->prog], Ojmp);
+ break;
+ case IMOVPC:
+ opwst(i, Omov, RAX);
+ genw(patch[i->s.imm]+(ulong)base);
+ break;
+ case IGOTO:
+ opwst(i, Olea, RBX);
+ opwld(i, Oldw, RAX);
+ gen2(Ojmprm, (0<<6)|(4<<3)|4);
+ genb((2<<6)|(RAX<<3)|RBX);
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)base + patch[t[0]];
+ t++;
+ }
+ break;
+ case IMULF:
+ arithf(i, 1);
+ break;
+ case IDIVF:
+ arithf(i, 7);
+ break;
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ mid(i, Oldw, RAX);
+ opwld(i, Oldw, RTMP);
+ if(i->op == IMULW)
+ gen2(0xf7, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf7, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODW)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ mid(i, Oldb, RAX);
+ opwld(i, Oldb, RTMP);
+ if(i->op == IMULB)
+ gen2(0xf6, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf6, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODB)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostb, RAX);
+ break;
+ case IINDX:
+ opwld(i, Oldw, RTMP); // MOVW xx(s), BX
+
+ if(bflag){
+ opwst(i, Oldw, RAX);
+ modrm(0x3b, O(Array, len), RTMP, RAX); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ modrm(Oldw, O(Array, t), RTMP, RTA);
+ modrm(0xf7, O(Type, size), RTA, 5); /* IMULL AX, xx(t) */
+ }
+ else{
+ modrm(Oldw, O(Array, t), RTMP, RAX); // MOVW t(BX), AX
+ modrm(Oldw, O(Type, size), RAX, RAX); // MOVW size(AX), AX
+ if(UXDST(i->add) == DST(AIMM)) {
+ gen2(0x69, (3<<6)|(RAX<<3)|0);
+ genw(i->d.imm);
+ }
+ else
+ opwst(i, 0xf7, 5); // IMULL AX,xx(d)
+ }
+
+ modrm(0x03, O(Array, data), RBX, RAX); // ADDL data(BX), AX
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDB:
+ r = 0;
+ goto idx;
+ case IINDF:
+ case IINDL:
+ r = 3;
+ goto idx;
+ case IINDW:
+ r = 2;
+ idx:
+ opwld(i, Oldw, RAX);
+ opwst(i, Oldw, RTMP);
+ if(bflag){
+ modrm(0x3b, O(Array, len), RAX, RTMP); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ }
+ modrm(Oldw, O(Array, data), RAX, RAX);
+ gen2(Olea, (0<<6)|(0<<3)|4); /* lea (AX)(RTMP*r) */
+ genb((r<<6)|(RTMP<<3)|RAX);
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDC:
+ opwld(i, Oldw, RAX); // string
+ mid(i, Oldw, RBX); // index
+ if(bflag){
+ modrm(Oldw, O(String, len), RAX, RTA);
+ cmpl(RTA, 0);
+ gen2(Ojltb, 16);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4);
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ gen2(Ojmpb, 11);
+ gen2(Oneg, (3<<6)|(3<<3)|RTA);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x73, 0xee); /* JNB */
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4);
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ opwst(i, Ostw, RAX);
+ break;
+ }
+ modrm(Ocmpi, O(String, len), RAX, 7);
+ genb(0);
+ gen2(Ojltb, 7);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4); /* movzbx 12(AX)(RBX*1), RAX */
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ gen2(Ojmpb, 5);
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4); /* movzwx 12(AX)(RBX*4), RAX */
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ opwst(i, Ostw, RAX);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IMOVL:
+ opwld(i, Olea, RTA);
+ opwst(i, Olea, RTMP);
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ostw, 4, RTMP, RAX);
+ break;
+ case IADDL:
+ larith(i, 0x03, 0x13);
+ break;
+ case ISUBL:
+ larith(i, 0x2b, 0x1b);
+ break;
+ case IORL:
+ larith(i, 0x0b, 0x0b);
+ break;
+ case IANDL:
+ larith(i, 0x23, 0x23);
+ break;
+ case IXORL:
+ larith(i, 0x33, 0x33);
+ break;
+ case IBEQL:
+ cbral(i, Ojnel, Ojeql, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Ojnel, Ojnel, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Ojltl, Ojbel, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Ojgtl, Ojal, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Ojltl, Ojbl, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Ojgtl, Ojael, EQAND);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(32);
+ if(comvec == nil)
+ error(exNomem);
+ code = (uchar*)comvec;
+
+ genb(Opushl+RBX);
+ genb(Opushl+RCX);
+ genb(Opushl+RDX);
+ genb(Opushl+RSI);
+ genb(Opushl+RDI);
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ modrm(Ojmprm, O(REG, PC), RTMP, 4);
+}
+
+static void
+maccase(void)
+{
+ uchar *loop, *def, *lab1;
+
+ modrm(Oldw, 0, RSI, RDX); // n = t[0]
+ modrm(Olea, 4, RSI, RSI); // t = &t[1]
+ gen2(Oldw, (3<<6)|(RBX<<3)|RDX); // MOVL DX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RDX<<3)|RBX); // ADDL DX, BX BX = n*3
+ gen2(Opushrm, (0<<6)|(6<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // PUSHL 0(SI)(BX*4)
+ loop = code;
+ cmpl(RDX, 0);
+ gen2(Ojleb, 0);
+ def = code-1;
+ gen2(Oldw, (3<<6)|(RCX<<3)|RDX); // MOVL DX, CX n2 = n
+ gen2(Oshr, (3<<6)|(5<<3)|RCX); // SHR CX,1 n2 = n2>>1
+ gen2(Oldw, (3<<6)|(RBX<<3)|RCX); // MOVL CX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RCX<<3)|RBX); // ADDL CX, BX BX = n2*3
+ gen2(0x3b, (0<<6)|(RAX<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // CMPL AX, 0(SI)(BX*4)
+ gen2(Ojgeb, 0); // JGE lab1
+ lab1 = code-1;
+ gen2(Oldw, (3<<6)|(RDX<<3)|RCX);
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(0x3b, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 4); // CMPL AX, 4(SI)(BX*4)
+ gen2(Ojltb, 0);
+ lab1 = code-1;
+ gen2(Olea, (1<<6)|(RSI<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 12); // LEA 12(SI)(RBX*4), RSI
+ gen2(0x2b, (3<<6)|(RDX<<3)|RCX); // SUBL CX, DX n -= n2
+ gen2(Odecrm, (3<<6)|(1<<3)|RDX); // DECL DX n -= 1
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(Oldw, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 8); // MOVL 8(SI)(BX*4), AX
+ genb(Opopl+RSI); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *def = code-def-1; // def:
+ genb(Opopl+RAX); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+}
+
+static void
+macfrp(void)
+{
+ cmpl(RAX, (ulong)H); // CMPL AX, $H
+ gen2(Ojneb, 0x01); // JNE .+1
+ genb(Oret); // RET
+ modrm(0x83, O(Heap, ref)-sizeof(Heap), RAX, 7);
+ genb(0x01); // CMP AX.ref, $1
+ gen2(Ojeqb, 0x04); // JNE .+4
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RAX, 1);
+ genb(Oret); // DEC AX.ref
+ // RET
+ con((ulong)&R, RTMP); // MOV $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ modrm(Ostw, O(REG, s), RTMP, RAX); // MOVL RAX, R.s
+ bra((ulong)rdestroy, Ocall); // CALL rdestroy
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ genb(Oret);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ uchar *s;
+ static ulong lpunt, lnomr, lfrmr, linterp;
+
+ s = code;
+
+ lpunt -= 2;
+ lnomr -= 2;
+ lfrmr -= 2;
+ linterp -= 2;
+
+ con(0, RBX); // MOVL $0, RBX
+ modrm(Oldw, O(Frame, t), RFP, RAX); // MOVL t(FP), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Oldw, O(Type, destroy), RAX, RAX);// MOVL destroy(RAX), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, fp), RFP, RBX); // CMPL fp(FP), RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, mr), RFP, RBX); // CMPL mr(FP), RBX
+ gen2(Ojeqb, lnomr-(code-s)); // JEQ lnomr
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RTA, 1);
+ gen2(Ojneb, lfrmr-(code-s)); // JNE lfrmr
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ gen2(Ojmpb, lpunt-(code-s)); // JMP lpunt
+ lfrmr = code - s;
+ modrm(Oldw, O(Frame, mr), RFP, RTA); // MOVL mr(FP), RTA
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL MP(RTA), RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ gen2(Ojeqb, linterp-(code-s)); // JEQ linterp
+ lnomr = code - s;
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+
+ linterp = code - s; // return to uncompiled code
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL RAX, R.PC
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ genb(Opopl+RDI); // return to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ // label:
+ lpunt = code - s;
+
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RBX, 0);
+ gen2(Oldw, (0<<6)|(RAX<<3)|5); // INCL ref(BX)
+ genw((ulong)&mutator); // MOVL mutator, RAX
+ modrm(Ocmpw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ojneb, 0x01); // CMPL color(BX), RAX
+ genb(Oret); // MOVL $propagator,RTMP
+ con(propagator, RAX); // MOVL RTMP, color(BX)
+ modrm(Ostw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ostw, (0<<6)|(RAX<<3)|5); // can be any !0 value
+ genw((ulong)&nprop); // MOVL RBX, nprop
+ genb(Oret);
+}
+
+static void
+macmcal(void)
+{
+ uchar *label, *mlnil, *interp;
+
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ modrm(0x83, O(Modlink, prog), RTA, 7); // CMPL $0, ml->prog
+ genb(0x00);
+ gen2(Ojneb, 0); // JNE patch
+ label = code-1;
+ *mlnil = code-mlnil-1;
+ modrm(Ostw, O(REG, FP), RTMP, RCX);
+ modrm(Ostw, O(REG, dt), RTMP, RAX);
+ bra((ulong)rmcall, Ocall); // CALL rmcall
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+ *label = code-label-1; // patch:
+ gen2(Oldw, (3<<6)|(RFP<<3)|RCX); // MOVL CX, RFP R.FP = f
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL R.M->mp, RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP R.MP = ml->MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ genb(Opopl+RTA); // balance call
+ gen2(Ojeqb, 0); // JEQ interp
+ interp = code-1;
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *interp = code-interp-1; // interp:
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI); // call to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+static void
+macfram(void)
+{
+ uchar *label;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, SP), RTMP, RAX); // MOVL R.SP, AX
+ modrm(0x03, O(Type, size), RTA, RAX); // ADDL size(RCX), RAX
+ modrm(0x3b, O(REG, TS), RTMP, RAX); // CMPL AX, R.TS
+ gen2(0x7c, 0x00); // JL .+(patch)
+ label = code-1;
+
+ modrm(Ostw, O(REG, s), RTMP, RTA);
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ bra((ulong)extend, Ocall); // CALL extend
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ modrm(Oldw, O(REG, s), RTMP, RCX); // MOVL R.s, *R.d
+ genb(Oret); // RET
+ *label = code-label-1;
+ modrm(Oldw, O(REG, SP), RTMP, RCX); // MOVL R.SP, CX
+ modrm(Ostw, O(REG, SP), RTMP, RAX); // MOVL AX, R.SP
+
+ modrm(Ostw, O(Frame, t), RCX, RTA); // MOVL RTA, t(CX) f->t = t
+ modrm(Omov, REGMOD*4, RCX, 0); // MOVL $0, mr(CX) f->mr
+ genw(0);
+ modrm(Oldw, O(Type, initialize), RTA, RTA);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA); // JMP*L RTA
+ genb(Oret); // RET
+}
+
+static void
+macmfra(void)
+{
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+ modrm(Ostw, O(REG, s), RTMP, RAX); // Save type
+ modrm(Ostw, O(REG, d), RTMP, RTA); // Save destination
+ bra((ulong)rmfram, Ocall); // CALL rmfram
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+}
+
+static void
+macrelq(void)
+{
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ genb(Opopl+RAX);
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ modrm(Oldw, j, RFP, RAX);
+ rbra(macro[MacFRP], Ocall);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RAX);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ modrm(Ostw, j, RCX, RAX);
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ uchar *tmp;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(uchar), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ if(cflag > 3)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ ulong v;
+ Modl *e;
+ Link *l;
+ int i, n;
+ uchar *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = mallocz(4096*sizeof(uchar),0);
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ n = (n+3)&~3;
+
+ nlit *= sizeof(ulong);
+ base = mallocz(n + nlit, 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d 386=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = (ulong*)(base+n);
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 4) {
+ print("%D\n", &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++)
+ mactab[i].gen();
+
+ v = (ulong)base;
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(v+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(base);
+ return 0;
+}
+
diff --git a/libinterp/comp-68020.c b/libinterp/comp-68020.c
new file mode 100644
index 00000000..0c5e9b7c
--- /dev/null
+++ b/libinterp/comp-68020.c
@@ -0,0 +1,2074 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+enum
+{
+ RAX = 0,
+ RCX = 1, /* Be careful with RCX, smashed in bra() */
+ RTA = 2,
+ RTMP = 3,
+ RFP = 4,
+ RMP = 5,
+ R7 = 7,
+
+ DTMP = 0,
+ DTMP1 = 1,
+ DTMP2 = 2,
+ DTMP3 = 3,
+
+ Oadd = 0xD000,
+ OaddaR = 0xD1E8, /* ADDA (d16,Rr), Rr */
+ Oaddi = 0x0600,
+ OaddRD = 0xD0A8,
+ OaslbD = 0xE120,
+ OaslwD = 0xE1A0,
+ OasrbD = 0xE020,
+ OasrwD = 0xE0A0,
+ Oand = 0xC000,
+ Oandi = 0x0200,
+ Obra = 0x6000,
+ Obsr = 0x6100,
+ OclrwD = 0x4280,
+ OcmpiwR = 0x0CA8, /* cmpi.l offset(Rrm), imm.long */
+ OcmpwR = 0xB1E8, /* cmpa $offset(Rrm), Rr */
+ OcmpbD = 0xB028, /* cmp.b $offset(Rrm), Dr */
+ OcmpwD = 0xB0A8, /* cmp.l $offset(Rx), Dr */
+ OcmpwDD = 0xB080, /* cmp.l Dr, Dx */
+ Odbeq = 0x57C8,
+ OdecrwRind = 0x53A8, /* SUBQ.L $0x1, offset(Rr) */
+ Odivs = 0x81C0,
+ Oeor = 0xB000,
+ Oeori = 0x0A00,
+ OexgRR = 0xC148, /* exg Rx, Ry */
+ Oextw = 0x4880, /* EXT.W Dx extend byte to 16-bit */
+ Oextbw = 0x49C0, /* EXTB.L Dx extend byte to 32-bit */
+ OincrwR = 0x5288, /* ADDQ.L $0x1, Rr */
+ OincrwRind = 0x52A8, /* ADDQ.L $0x1, offset(Rr) */
+ Ojhi = 0x6200, /* BHI */
+ Ojhs = 0x6400, /* BCC(HS) */
+ Ojlo = 0x6500, /* BCS(LO) */
+ Ojls = 0x6300, /* BLS */
+ Ojeq = 0x6700, /* BEQ */
+ Ojge = 0x6C00, /* BGE */
+ Ojgt = 0x6E00, /* BGT */
+ Ojle = 0x6F00, /* BLE */
+ Ojlt = 0x6D00, /* BLT */
+ Ojne = 0x6600, /* BNE */
+ OjmpRind= 0x4ED0, /* jmp (Rn) */
+ OjmpRindoffs= 0x4EE8, /* jmp $offs(Rn) */
+ OjsrRind= 0x4E90,
+ OldbD = 0x1028, /* $offset(Rrm).b -> Dr */
+ OldbR = 0x1058, /* $offset(Rrm).b -> Rr */
+ OldwD = 0x2028, /* $offset(Rrm) -> Dr */
+ OldwR = 0x2068, /* $offset(Rrm) -> Rr */
+ OleaR = 0x41E8, /* addr($offset(Rrm) -> Rr */
+ OlslD = 0xE388,
+ Olsl2D = 0xE588,
+ OlsrD = 0xE288,
+ OlslbD = 0xE128,
+ OlslwD = 0xE1A8,
+ OlsrbD = 0xE028,
+ OlsrwD = 0xE0A8,
+ OmovelitwR= 0x207C, /* move $xx, Rr */
+ OmovelitwD= 0x203C, /* move $xx, Dr */
+ Omoveal = 0x2040,
+ OmovwR = 0x217C, /* imm.long -> $offset(Rrm) */
+ OmovwRR = 0x2048, /* movea.l Rr, Rx */
+ OmovwRD = 0x2008, /* move.l Rr, Dx */
+ Omuls = 0xC1C0,
+ OnegwD = 0x4480,
+ Oor = 0x8000,
+ Oori = 0x0000,
+ OpopwR = 0x205F, /* MOVEA.L (A7)+, Rr */
+ OpushwR = 0x2F08, /* MOVE.L Rr, -(A7) */
+ Opushil = 0x2F3C, /* MOVE.L imm., -(A7) */
+ OroxlD = 0xE390,
+ OroxrD = 0xE290,
+ Orts = 0x4E75,
+ OstbD = 0x1140, /* Dr.b -> $offset(Rrm) !!!!! ostbR does NOT exist */
+ OstwD = 0x2140, /* Dr -> $offset(Rrm) */
+ OstwR = 0x2148, /* Rr -> $offset(Rrm) */
+ Osub = 0x9000,
+ Osubi = 0x0400,
+ OaddqwR = 0x5088,
+ Oswap = 0x4840,
+ OtstbD = 0x4A00, /* tst.b Dr */
+ OtstwR = 0x4AA8, /* tst.l $offset(Rx) */
+ Oill = 0x4afc, /* illegal instruction trap */
+ Onop = 0x4E71,
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ NMACRO
+};
+
+static uchar* code;
+static uchar* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(uchar*, int);
+
+extern void _mull(void);
+extern void _divsl(void);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+} mactab[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacFRAM, macfram, /* frame instruction */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static int
+bc(int o)
+{
+ if(o < 127 && o > -128)
+ return 1;
+ return 0;
+}
+
+static int
+wc(int o)
+{
+ if(o < 65535 && o > -65536)
+ return 1;
+ return 0;
+}
+
+static void
+urk(void)
+{
+ error(exCompile);
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+ code[0] = o1;
+ code[1] = o2;
+ code += 2;
+}
+
+static void
+genw(ulong o)
+{
+ code[0] = (o>>8)&0xFF;
+ code[1] = o&0xFF;
+ code += 2;
+}
+
+static void
+genl(ulong o)
+{
+ *(ulong*)code = o;
+ code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+ switch (inst) {
+ case OstwD:
+ case OstwR:
+ case OstbD:
+ if (!disp) {
+ inst&=0xfe3f;
+ inst|=0x0080;
+ }
+ genw(inst | (rm<<9) | r);
+ if (disp)
+ genw(disp);
+ break;
+ case Oadd|0x28|(0x6<<6):
+ case Oadd|0x28|(0x4<<6):
+ case Osub|0x28|(0x6<<6):
+ case Osub|0x28|(0x4<<6):
+ case Oor|0x28|(0x6<<6):
+ case Oor|0x28|(0x4<<6):
+ case Oand|0x28|(0x6<<6):
+ case Oand|0x28|(0x4<<6):
+ case Oeor|0x28|(0x6<<6):
+ case Oeor|0x28|(0x4<<6):
+ case Oaddi|0x28|(0x2<<6):
+ case Oori|0x28|(0x2<<6):
+ case Oandi|0x28|(0x2<<6):
+ case Oeori|0x28|(0x2<<6):
+ case Osubi|0x28|(0x2<<6):
+ case Oaddi|0x28:
+ case Oori|0x28:
+ case Oandi|0x28:
+ case Oeori|0x28:
+ case Osubi|0x28:
+ case OldbD:
+ case OldwD:
+ case OldwR:
+ case OldbR:
+ case OleaR:
+ case OaddRD:
+ case OcmpwR:
+ case OcmpwD:
+ case OcmpbD:
+ case OdecrwRind:
+ case OincrwRind:
+ case OtstwR:
+ if (!disp) {
+ inst&=0xffc7;
+ inst|=0x0010;
+ }
+ genw(inst | (r<<9) | rm);
+ if (disp)
+ genw(disp);
+ break;
+ default:
+ print("modrm: urk on opcode 0x%ux\n",inst);
+ urk();
+ }
+}
+
+static void
+conR(ulong o, int r)
+{
+ if(o == 0) {
+ genw(0x91C8|(r<<9)|r); /* SUBA Rr, Rr */
+ return;
+ }
+ genw(Omoveal|(r<<9)|0x7C); /* MOVEA.L $o,Rr */
+ genl(o);
+}
+
+static void
+conD(ulong o, int r)
+{
+ if(o == 0) {
+ genw(OclrwD|r); /* CLR.L Dr */
+ return;
+ }
+ genw(OmovelitwD|(r<<9)); /* MOVEA.L $o,Dr */
+ genl(o);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ modrm(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ modrm(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ conR(i->s.imm, r);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == OleaR)
+ rta = r;
+ modrm(OldwR, i->s.i.f, ir, rta);
+ modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwldD(Inst *i, int mi, int r)
+{
+ int ir, rta;
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ modrm(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ modrm(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ conD(i->s.imm, r);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ modrm(OldwR, i->s.i.f, ir, rta);
+ modrm(mi, i->s.i.s, rta, r);
+}
+
+static int
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ conR(i->d.imm, r);
+ return 0;
+ case DST(AFP):
+ modrm(mi, i->d.ind, RFP, r);
+ return i->d.ind;
+ case DST(AMP):
+ modrm(mi, i->d.ind, RMP, r);
+ return i->d.ind;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == OleaR)
+ rta = r;
+ modrm(OldwR, i->d.i.f, ir, rta);
+ modrm(mi, i->d.i.s, rta, r);
+ return i->d.i.s;
+}
+
+static void
+opwstD(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ conD(i->d.imm, r);
+ return;
+ case DST(AFP):
+ modrm(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ modrm(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == OleaR)
+ rta = r;
+ modrm(OldwR, i->d.i.f, ir, rta);
+ modrm(mi, i->d.i.s, rta, r);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Ojge:
+ return Ojlt;
+ case Ojle:
+ return Ojgt;
+ case Ojgt:
+ return Ojle;
+ case Ojlt:
+ return Ojge;
+ case Ojhi:
+ return Ojls;
+ case Ojlo:
+ return Ojhs;
+ case Ojhs:
+ return Ojlo;
+ case Ojls:
+ return Ojhi;
+ case Ojeq:
+ return Ojne;
+ case Ojne:
+ return Ojeq;
+ }
+ return b;
+}
+
+static void
+bra(ulong dst, int op)
+{
+ ulong ddst;
+ switch (op) {
+ case Obsr:
+ genw(OmovelitwR|(RCX<<9));
+ genl(dst);
+ genw(OjsrRind|RCX);
+ break;
+ case Obra:
+dojmp:
+ ddst=dst-((ulong)code+2);
+ if (bc(ddst)) {
+ genw(Obra|(uchar)ddst);
+ genw(Onop);
+ genw(Onop);
+ genw(Onop);
+ } else if (wc(ddst)) {
+ genw(Obra);
+ genw(ddst);
+ genw(Onop);
+ genw(Onop);
+ } else {
+ genw(OmovelitwR|(RCX<<9));
+ genl(dst);
+ genw(OjmpRind|RCX);
+ }
+ break;
+ case Ojhi:
+ case Ojhs:
+ case Ojlo:
+ case Ojls:
+ case Ojeq:
+ case Ojge:
+ case Ojgt:
+ case Ojle:
+ case Ojlt:
+ case Ojne:
+ genw(swapbraop(op)|0x8);
+ goto dojmp;
+ default:
+ print("bra: urk op opcode 0x%ux\n",op);
+ urk();
+ break;
+ }
+}
+
+static void
+rbra(ulong dst, int op)
+{
+ dst += (ulong)base;
+ bra(dst,op);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+ genw(OmovelitwR|(RAX<<9));
+ genl((ulong)litpool);
+ modrm(OstwR, roff, RTMP, RAX);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+ conR((ulong)&R, RTMP);
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ literal(i->s.imm, O(REG, s));
+ }
+ else {
+ opwld(i, OleaR, RAX);
+ modrm(OstwR, O(REG, s), RTMP, RAX);
+ }
+ }
+
+ if(m & DSTOP) {
+ if(UXDST(i->add) == DST(AIMM)) {
+ literal(i->d.imm, O(REG, d));
+ } else {
+ opwst(i, OleaR, RAX);
+ modrm(OstwR, O(REG, d), RTMP, RAX);
+ }
+ }
+ if(m & WRTPC) {
+ genw(OmovwR|(RTMP<<9));
+ pc = patch[i-mod->prog+1];
+ genl((ulong)base + pc);
+ genw(O(REG, PC));
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+
+ literal((ulong)base+pc, O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ modrm(OldwR, O(REG, d), RTMP, RAX);
+ modrm(OstwR, O(REG, m), RTMP, RAX);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ modrm(OleaR, i->reg, RFP, RAX);
+ modrm(OstwR, O(REG, m), RTMP, RAX);
+ break;
+ case AXINM:
+ modrm(OleaR, i->reg, RMP, RAX);
+ modrm(OstwR, O(REG, m), RTMP, RAX);
+ break;
+ }
+ modrm(OstwR, O(REG, FP), RTMP, RFP);
+
+ bra((ulong)fn, Obsr);
+
+ conR((ulong)&R, RTMP);
+ if(m & TCHECK) {
+ genw(Orts);
+ }
+
+ modrm(OldwR, O(REG, FP), RTMP, RFP);
+ modrm(OldwR, O(REG, MP), RTMP, RMP);
+
+ if(m & NEWPC) {
+ modrm(OldwR, O(REG, PC), RTMP, RAX);
+ genw(OjmpRind|RAX);
+ }
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ conR((short)i->reg, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ modrm(mi, i->reg, ir, r);
+}
+
+static void
+midD(Inst *i, int mi, int r)
+{
+ int ir;
+ switch(i->add&ARM) {
+ default:
+ opwstD(i, mi, r);
+ return;
+ case AXIMM:
+ conD((short)i->reg, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ modrm(mi, i->reg, ir, r);
+}
+
+static void
+arithimms(Inst *i, int opcode, int opmode)
+{
+ uchar off[3];
+ int hasoff;
+ if(i->add&ARM) {
+ midD(i,(opmode)?OldwD:OldbD,DTMP);
+ if (((opcode==Oaddi)||(opcode==Osubi))&&(i->s.imm>0)&&(i->s.imm<=8))
+ genw(0x5000|((opcode==Osubi)?0x100:0)|(((opmode)?0x2:0x0)<<6)|(((uchar)i->s.imm)<<9)|DTMP);
+ else {
+ genw(opcode|DTMP|(((opmode)?0x2:0)<<6));
+ if (opmode)
+ genl(i->s.imm);
+ else
+ genw(i->s.imm);
+ }
+ opwstD(i, (opmode)?OstwD:OstbD, DTMP);
+ return;
+ }
+ if (hasoff=opwst(i, opcode|0x28|(((opmode)?0x2:0)<<6), 0)) {
+ code-=2;
+ off[0]=code[0]; off[1]=code[1];
+ }
+ if (((opcode==Oaddi)||(opcode==Osubi))&&(i->s.imm>0)&&(i->s.imm<=8)) {
+ code-=2;
+ off[2]=code[1];
+ genw(0x5000|((opcode==Osubi)?0x100:0)|(((opmode)?0x2:0x0)<<6)|(((uchar)i->s.imm)<<9)|((hasoff)?0x28:0x10)|(off[2]&0x7));
+ }
+ else {
+ if (opmode)
+ genl(i->s.imm);
+ else
+ genw(i->s.imm);
+ }
+ if (hasoff)
+ gen2(off[0],off[1]);
+}
+
+static void
+arith(Inst *i, int opcode, int opmode)
+{
+ opwldD(i, (opmode)?OldwD:OldbD, DTMP1);
+ if(i->add&ARM) {
+ midD(i,(opmode)?OldwD:OldbD,DTMP);
+ genw(opcode|(DTMP<<9)|DTMP1|(((opmode)?0x2:0)<<6));
+ opwstD(i, (opmode)?OstwD:OstbD, DTMP);
+ return;
+ }
+ opwst(i, opcode|0x28|(((opmode)?0x6:0x4)<<6), DTMP1);
+}
+
+static void
+oldarithsub(Inst *i, int opmode)
+{
+ opwldD(i, (opmode)?OldwD:OldbD, DTMP1);
+ if(i->add&ARM)
+ midD(i,(opmode)?OldwD:OldbD,DTMP);
+ else
+ opwstD(i, (opmode)?OldwD:OldbD, DTMP);
+ genw(Osub|(DTMP<<9)|DTMP1|(((opmode)?0x2:0)<<6));
+ opwstD(i, (opmode)?OstwD:OstbD, DTMP);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op)
+{
+ midD(i, ld, DTMP);
+ opwldD(i, OldwD, DTMP1);
+ genw(op|(DTMP1<<9)|DTMP);
+ opwstD(i, st, DTMP);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+ genw(0xB1FC|(r<<9));
+ genl(v);
+}
+
+static int
+swapforcbra(int jmp) {
+ switch(jmp) {
+ case Ojge:
+ return Ojle;
+ case Ojle:
+ return Ojge;
+ case Ojgt:
+ return Ojlt;
+ case Ojlt:
+ return Ojgt;
+ case Ojhi:
+ return Ojlo;
+ case Ojlo:
+ return Ojhi;
+ case Ojhs:
+ return Ojls;
+ case Ojls:
+ return Ojhs;
+ default:
+ return jmp;
+ }
+
+}
+static void
+cbra(Inst *i, int jmp)
+{
+ midD(i, OldwD, DTMP);
+ if (UXSRC(i->add)==SRC(AIMM)) {
+ genw(0xB0BC|DTMP);
+ genl(i->s.imm);
+ }
+ else
+ opwldD(i,OcmpwD,DTMP);
+ rbra(patch[i->d.ins-mod->prog], swapforcbra(jmp));
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst;
+ uchar *label;
+ opwld(i, OleaR, RTMP);
+ mid(i, OleaR, RTA);
+ modrm(OldwR, 4, RTMP, RAX);
+ modrm(OcmpwR, 4, RTA, RAX);
+ label = 0;
+ dst = patch[i->d.ins-mod->prog];
+ switch(mode) {
+ case ANDAND:
+ genw(jmsw);
+ label = code-1;
+ break;
+ case OROR:
+ rbra(dst, jmsw);
+ break;
+ case EQAND:
+ rbra(dst, jmsw);
+ genw(Ojne);
+ label = code-1;
+ break;
+ }
+ modrm(OldwR, 0, RTMP, RAX);
+ modrm(OcmpwR, 0, RTA, RAX);
+ rbra(dst, jlsw);
+ if(label != nil)
+ *label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ midD(i, OldbD, DTMP);
+ opwldD(i,OcmpbD,DTMP);
+ rbra(patch[i->d.ins-mod->prog], swapforcbra(jmp));
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ USED (w);
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)base + patch[t[2]];
+ t += 3;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ uchar *punt, *mlnil;
+
+ opwld(i, OldwR, RAX);
+ cmpl(RAX, (ulong)H);
+ genw(Ojeq);
+ mlnil = code - 1;
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ modrm(OldwR, o, RAX, RTA);
+ modrm(OtstwR,O(Type, initialize),RTA,0);
+ genw(Ojne);
+ punt = code - 1;
+ genw(OexgRR|RAX|(RTA<<9));
+ opwst(i, OleaR, RTA);
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMFRA], Obsr);
+ rbra(patch[i-mod->prog+1], Obra);
+
+ *punt = code-punt-1;
+ rbra(macro[MacFRAM], Obsr);
+ opwst(i, OstwR, RAX);
+}
+
+static void
+commcall(Inst *i)
+{
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ opwld(i, OldwR, RTA);
+ genw(OmovwR|(RTA<<9)); // MOVL $.+1, lr(RTA) f->lr = R.PC
+ genl((ulong)base+patch[i-mod->prog+1]);
+ genw(O(Frame, lr));
+ modrm(OstwR, O(Frame, fp), RTA, RFP); // MOVL RFP, fp(RTA) f->fp = R.FP
+ modrm(OldwD, O(REG, M), RTMP, DTMP); // MOVL R.M, DTMP
+ modrm(OstwD, O(Frame, mr), RTA, DTMP); // MOVL RTA, mr(RTA) f->mr = R.M
+ opwst(i, OldwR, RAX); // MOVL ml, RAX
+ modrm(OldwD, O(Modlink, m), RAX, DTMP); // MOVL ml->m, DTMP
+ modrm(OldwR, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RAX, RAX);
+ rbra(macro[MacMCAL], Obsr);
+}
+
+static void
+laritha(Inst *i, int opc)
+{
+ if((i->add&ARM) != AXNON) {
+ mid(i, OleaR, RTMP);
+ opwst(i, OleaR, RTA);
+ genw(0x20D8|(RTA<<9)|RTMP); // MOVL (RTMP)+, (RTA)+
+ genw(0x20D8|(RTA<<9)|RTMP); // MOVL (RTMP)+, (RTA)+
+ }
+ else {
+ mid(i, OleaR, RTA);
+ genw(0x5088|RTA); // ADDQ.l #8, RTA
+ }
+
+ opwld(i, OleaR, RTMP);
+ genw(0x5088|RTMP); // ADDQ.l #8, RTMP
+
+ genw(0x44FC); // MOVE imm16, CCR
+ genw(0);
+ genw(opc|RTMP|(RTA<<9)); // ADDX (-RTMP), (-RTA)
+ genw(opc|RTMP|(RTA<<9)); // ADDX (-RTMP), (-RTA)
+}
+
+static void
+larith(Inst *i, int op)
+{
+ if((i->add&ARM) != AXNON) {
+ mid(i, OleaR, RTMP);
+ opwst(i, OleaR, RTA);
+ genw(0x20D8|RTMP|(RTA<<9)); // MOVL (RTMP)+, (RTA)+
+ genw(0x2090|RTMP|(RTA<<9)); // MOVL (RTMP), (RTA)
+ genw(0x5988|RTA); // SUBQ.l #4, RTA
+ }
+ else
+ mid(i, OleaR, RTA);
+
+
+ opwld(i, OleaR, RTMP);
+ genw(0x2018|RTMP|(DTMP<<9)); // MOVL (RTMP+), DTMP
+ genw(op|RTA|(DTMP<<9)); // ORL DTMP, (RTA+)
+ genw(0x2010|(DTMP<<9)|RTMP); // MOVL (RTMP) DTMP
+ genw((op&0xFFF7)|RTA|(DTMP<<9)); // ORL DTMP, (RTA)
+}
+
+static void
+shll(Inst *i)
+{
+ uchar *label;
+
+ opwldD(i, OldwD, DTMP); // The number of shifts -> DTMP
+ mid(i, OleaR, RTA); // LEA source, RTA
+ genw(0x2018|(DTMP1<<9)|RTA); // move (RTA+), DTMP1
+ genw(0x2010|(DTMP2<<9)|RTA); // move (RTA), DTMP2
+
+ genw(Obra);
+ label=code-1;
+
+ genw(OlslD|DTMP2);
+ genw(OroxlD|DTMP1);
+ *label=code-label-1;
+ genw(Odbeq);
+ genw(label-code+1);
+
+ opwst(i, OleaR, RTA);
+ genw(0x2080|(RTA<<9)|DTMP2); // move DTMP2, (RTA)
+ genw(0x2100|(RTA<<9)|DTMP1); // move DTMP1, (-RTA)
+}
+
+static void
+shrl(Inst *i)
+{
+ uchar *label;
+
+ opwldD(i, OldwD, DTMP); // The number of shifts -> DTMP
+ mid(i, OleaR, RTA); // LEA source, RTA
+ genw(0x2018|(DTMP1<<9)|RTA); // move (RTA+), DTMP1
+ genw(0x2010|(DTMP2<<9)|RTA); // move (RTA), DTMP2
+
+ genw(Obra);
+ label=code-1;
+
+ genw(OlsrD|DTMP2);
+ genw(OroxrD|DTMP1);
+ *label=code-label-1;
+ genw(Odbeq);
+ genw(label-code+1);
+
+ opwst(i, OleaR, RTA);
+ genw(0x2080|(RTA<<9)|DTMP2); // move DTMP2, (RTA)
+ genw(0x2100|(RTA<<9)|DTMP1); // move DTMP1, (-RTA)
+}
+
+static int myic;
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int r;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case ILOAD:
+ case IMSPAWN:
+ case ISLICEA:
+ case ISLICELA:
+ case ISLICEC:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWA:
+ case INEW:
+ case ICONSB:
+ case ICONSW:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTCA:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ genw(OclrwD| DTMP);
+ opwldD(i, OldbD, DTMP);
+ opwstD(i, OstwD, DTMP);
+ break;
+ case ICVTWB:
+ opwldD(i, OldwD, DTMP);
+ opwstD(i, OstbD, DTMP);
+ break;
+ case ICVTFW:
+ case ICVTWF:
+ case ICVTLF:
+ case ICVTFL:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case IHEADM:
+ case IMOVM:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IRET:
+ rbra(macro[MacRET], Obra);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ conR((ulong)mod->type[i->s.imm], RTA);
+ rbra(macro[MacFRAM], Obsr);
+ opwst(i, OstwR, RAX);
+ break;
+ case ILEA:
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ genw(Obra|4);
+ genl(i->s.imm);
+ conR((ulong)(code-4), RAX);
+ }
+ else
+ opwld(i, OleaR, RAX);
+ opwst(i, OstwR, RAX);
+ break;
+ case IHEADW:
+ opwld(i, OldwR, RAX);
+ modrm(OldwR, OA(List, data), RAX, RAX);
+ opwst(i, OstwR, RAX);
+ break;
+ case IHEADF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case IHEADB:
+ opwld(i, OldwR, RAX);
+ modrm(OldbD, OA(List, data), RAX, DTMP);
+ opwstD(i, OstbD, DTMP);
+ break;
+ case ITAIL:
+ opwld(i, OldwR, RAX);
+ modrm(OldwR, O(List, tail), RAX, RTMP);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, OldwR, RTMP);
+ if(i->op == IHEADP)
+ modrm(OldwR, OA(List, data), RTMP, RTMP);
+ movp:
+ {uchar *label;
+ cmpl(RTMP, (ulong)H);
+ genw(Ojeq);
+ label=code-1;
+ rbra(macro[MacCOLR], Obsr);
+ *label=code-label-1;
+ opwst(i, OldwR, RAX);
+ opwst(i, OstwR, RTMP);
+ rbra(macro[MacFRP], Obsr);
+ }
+ break;
+ case ILENA:
+ opwld(i, OldwR, RTMP);
+ conR(0, RAX);
+ cmpl(RTMP, (ulong)H);
+ genw(Ojeq|0x2);
+ modrm(OldwR, O(Array, len), RTMP, RAX);
+ opwst(i, OstwR, RAX);
+ break;
+ case ILENC:
+ {uchar *label;
+ opwld(i, OldwR, RTMP);
+ conD(0, DTMP);
+ cmpl(RTMP, (ulong)H);
+ genw(Ojeq);
+ label=code-1;
+ modrm(OldwD, O(String, len), RTMP, DTMP);
+ genw(0x4A80|RAX); // TSTL DTMP
+ genw(Ojge|0x02);
+ genw(OnegwD|DTMP);
+ *label=code-label-1;
+ opwstD(i, OstwD, DTMP);
+ }
+ break;
+ case ILENL:
+ {uchar *label,*l2;
+ conR(0, RAX);
+ opwld(i, OldwR, RTMP);
+ l2=code-1;
+ cmpl(RTMP, (ulong)H);
+ genw(Ojeq);
+ label=code-1;
+ modrm(OldwR, O(List, tail), RTMP, RTMP);
+ genw(OincrwR|RAX);
+ genw(Obra|(uchar)(l2-code-1));
+ *label=code-label-1;
+ opwst(i, OstwR, RAX);
+ }
+ break;
+ case IBEQF:
+ case IBNEF:
+ case IBLEF:
+ case IBLTF:
+ case IBGEF:
+ case IBGTF:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case IBEQW:
+ cbra(i, Ojeq);
+ break;
+ case IBLEW:
+ cbra(i, Ojle);
+ break;
+ case IBNEW:
+ cbra(i, Ojne);
+ break;
+ case IBGTW:
+ cbra(i, Ojgt);
+ break;
+ case IBLTW:
+ cbra(i, Ojlt);
+ break;
+ case IBGEW:
+ cbra(i, Ojge);
+ break;
+ case IBEQB:
+ cbrab(i, Ojeq);
+ break;
+ case IBLEB:
+ cbrab(i, Ojls);
+ break;
+ case IBNEB:
+ cbrab(i, Ojne);
+ break;
+ case IBGTB:
+ cbrab(i, Ojhi);
+ break;
+ case IBLTB:
+ cbrab(i, Ojlo);
+ break;
+ case IBGEB:
+ cbrab(i, Ojhs);
+ break;
+ case ISUBW:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Osubi,1);
+ else
+ arith(i, Osub, 1);
+ break;
+ case ISUBB:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Osubi,1);
+ else
+ arith(i, Osub, 0);
+ break;
+ case ISUBF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IADDW:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Oaddi,1);
+ else
+ arith(i, Oadd, 1);
+ break;
+ case IADDB:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Oaddi,0);
+ else
+ arith(i, Oadd, 0);
+ break;
+ case IADDF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IORW:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Oori,1);
+ else
+ arith(i, Oor, 1);
+ break;
+ case IORB:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Oori,0);
+ else
+ arith(i, Oor, 0);
+ break;
+ case IANDW:
+ arith(i, Oand, 1);
+ break;
+ case IANDB:
+ arith(i, Oand, 0);
+ break;
+ case IXORW:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Oeori,1);
+ else
+ arith(i, Oeor, 1);
+ break;
+ case IXORB:
+ if (UXSRC(i->add)==SRC(AIMM))
+ arithimms(i,Oeori,0);
+ else
+ arith(i, Oeor, 0);
+ break;
+ case ISHLW:
+ shift(i, OldwD, OstwD, OaslwD);
+ break;
+ case ISHLB:
+ shift(i, OldbD, OstbD, OaslbD);
+ break;
+ case ISHRW:
+ shift(i, OldwD, OstwD, OasrwD);
+ break;
+ case ISHRB:
+ shift(i, OldbD, OstbD, OasrbD);
+ break;
+ case IMOVF:
+ case INEGF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case IMOVB:
+ opwldD(i, OldbD, DTMP);
+ opwstD(i, OstbD, DTMP);
+ break;
+ case IMOVW:
+ opwldD(i, OldwD, DTMP);
+ opwstD(i, OstwD, DTMP);
+ break;
+ case ICVTLW:
+ case ICVTWL:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICALL:
+ opwld(i, OldwR, RAX);
+ genw(OmovwR|(RAX<<9)); // MOVL $.+1, lr(AX)
+ genl((ulong)base+patch[i-mod->prog+1]);
+ genw(O(Frame, lr));
+ modrm(OstwR, O(Frame, fp), RAX, RFP); // MOVL RFP, fp(AX)
+ genw(OmovwRR|(RFP<<9)|RAX); // MOVL AX,RFP
+ /* no break */
+ case IJMP:
+ rbra(patch[i->d.ins-mod->prog], Obra);
+ break;
+ case IGOTO:
+ opwst(i, OleaR, RTMP);
+ opwldD(i, OldwD, DTMP);
+ genw(OlslwD|DTMP);
+ genw(Oadd|(RTMP<<9)|(7<<6)|DTMP);
+ genw(OjmpRind|RTMP);
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)base + patch[t[0]];
+ t++;
+ }
+ break;
+ case IMULF:
+ case IDIVF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ opwld(i, OldwR, RAX);
+ genw(OpushwR|RAX);
+ mid(i, OldwR, RAX);
+ genw(OpushwR|RAX);
+ switch(i->op) {
+ case IMULW:
+ bra((ulong)_mull,Obsr);
+ genw(OaddqwR|(4<<9)|R7);
+ genw(OpopwR|(RAX<<9));
+ break;
+ case IMODW:
+ bra((ulong)_divsl,Obsr);
+ genw(OaddqwR|(4<<9)|R7);
+ genw(OpopwR|(RAX<<9));
+ break;
+ case IDIVW:
+ bra((ulong)_divsl,Obsr);
+ genw(OpopwR|(RAX<<9));
+ genw(OaddqwR|(4<<9)|R7);
+ break;
+ }
+ opwst(i, OstwR, RAX);
+ break;
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ midD(i, OldbD, DTMP);
+ genw(Oextw|DTMP);
+ opwldD(i, OldbD, DTMP2);
+ if (i->op == IMULB)
+ if(i->op == IMULB) {
+ genw(Oextw|DTMP2);
+ genw(Omuls|(DTMP<<9)|DTMP2);
+ }
+ else {
+ genw(Oextbw|DTMP2);
+ genw(Odivs|(DTMP<<9)|DTMP2);
+ }
+ if (i->op == IMODB)
+ genw(Oswap|DTMP);
+ opwstD(i, OstbD, DTMP);
+ break;
+ case IINDX:
+ opwld(i, OldwR, RTMP); // MOVW xx(s), RTMP
+ modrm(OldwR, O(Array, t), RTMP, RAX); // MOVW t(RTMP), AX
+ modrm(OldwD, O(Type, size), RAX, DTMP1); // MOVW size(AX), DTMP1
+ opwstD(i, OldwD, DTMP2); // MOVW indx, DTMP2
+ genl(0x70204283); // loop to MULW DTMP1, DTMP2, DTMP3
+ genl(0xe2996402);
+ genl(0xd682e38a);
+ genl(0x57c8fff6);
+
+ modrm(OldwR, O(Array, data), RTMP, RTMP);
+ genw(Oadd|(DTMP3<<9)|0x0088|RTMP); // ADDL data(RTMP), DTMP3
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(OstwD, i->reg, r, DTMP3);
+ break;
+ case IINDB:
+ r = 0;
+ goto idx;
+ case IINDF:
+ punt(i, SRCOP|THREOP|DSTOP, optab[i->op]);
+ break;
+ case IINDL:
+ r = 3;
+ goto idx;
+ case IINDW:
+ r = 2;
+ idx:
+ opwld(i, OldwR, RAX);
+ opwstD(i, OldwD, DTMP);
+ modrm(OldwR, O(Array, data), RAX, RTMP);
+
+ if (r)
+ genw(0xE188|(r<<9)|DTMP);
+ genw(Oadd|(RTMP<<9)|(7<<6)|DTMP); /* lea (AX)(DTMP*r) */
+
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(OstwR, i->reg, r, RTMP);
+ break;
+ case IINDC:
+ { uchar *label;
+ opwld(i, OldwR, RAX); // string
+ midD(i, OldwD, DTMP); // index
+ modrm(OtstwR,O(String, len),RAX,0);
+ modrm(OleaR, O(String, data), RAX, RAX);
+ genw(Ojge); // Ascii only, jump
+ label=code-1;
+
+ genw(OnegwD|DTMP);
+ genw(Olsl2D|DTMP); // << 2; index is times 4 bytes
+ genw(Oadd|(RAX<<9)|0x01C0|DTMP);
+ modrm(OldwD, 0, RAX, DTMP);
+ genw(Obra|0x4);
+ *label=code-label-1;
+ genw(Oadd|(RAX<<9)|0x01C0|DTMP);
+ modrm(OldbD, 0, RAX, DTMP);
+
+ opwst(i, OstwD, DTMP);
+ }
+ break;
+ case ICASE:
+ comcase(i, 1);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IMOVL:
+ opwld(i, OleaR, RTA);
+ opwst(i, OleaR, RTMP);
+ genw(0x20D8|(RTMP<<9)|RTA); // MOVE.l (RTA+), (RTMP+)
+ genw(0x2090|(RTMP<<9)|RTA); // MOVE.l (RTA), (RTMP)
+ break;
+ case IADDL:
+ laritha(i, 0xD188); // ADDX.l (-R0), (-R0)
+ break;
+ case ISUBL:
+ laritha(i, 0x9188); // SUBX.l (-R0), (-R0)
+ break;
+ case IORL:
+ larith(i, 0x8198); // OR.l D0, (R0+)
+ break;
+ case IANDL:
+ larith(i, 0xC198); // AND.l D0, (R0+)
+ break;
+ case IXORL:
+ larith(i, 0xB198); // EOR.l D0, (R0+)
+ break;
+ case IBEQL:
+ cbral(i, Ojne, Ojeq, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Ojne, Ojne, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Ojlt, Ojls, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Ojgt, Ojhi, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Ojlt, Ojlo, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Ojgt, Ojhs, EQAND);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ uchar *s;
+ if(comvec)
+ return;
+
+ comvec = malloc(32);
+ if(comvec == nil)
+ error(exNomem);
+ code = (uchar*)comvec;
+ s = code;
+
+ conR((ulong)&R, RAX);
+ modrm(OldwR, O(REG, FP), RAX, RFP);
+ modrm(OldwR, O(REG, MP), RAX, RMP);
+ modrm(OldwR, O(REG, PC), RAX, RAX);
+ genw(OjmpRind|RAX);
+
+ segflush(comvec, 32);
+
+ if(cflag > 2) {
+ print("preamble\n");
+ das(s, code-s);
+ }
+}
+
+static void
+maccase(void)
+{
+ /* Not used yet, done with punt() */
+}
+
+static void
+macfrp(void)
+{
+ uchar *label,*s;
+ s=code;
+ cmpl(RAX, (ulong)H); // CMPL AX, $H
+ genw(Ojne|0x2); // JNE .+2
+ genw(Orts); // RET
+ genw(OcmpiwR|(RAX<<9));
+ genl(0x01); // CMP AX.ref, $1
+ genw(O(Heap, ref)-sizeof(Heap));
+ genw(Ojeq); // JEQ
+ label=code-1;
+ modrm(OdecrwRind, O(Heap, ref)-sizeof(Heap), RAX, 0); // DEC AX.ref
+ genw(Orts); // RET
+ *label=code-label-1;
+
+ conR((ulong)&R, RTMP); // MOV $R, RTMP
+ modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ modrm(OstwR, O(REG, s), RTMP, RAX); // MOVL RAX, R.s
+ // CALL rdestroy
+ bra((ulong)rdestroy, Obsr);
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OldwR, O(REG, FP), RTMP, RFP); // MOVL R.FP, RFP
+ modrm(OldwR, O(REG, MP), RTMP, RMP); // MOVL R.MP, RMP
+ genw(Orts);
+ if(pass&&(cflag > 2)) {
+ print("macfrp\n");
+ das(s, code-s);
+ }
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ uchar *s;
+ static ulong lpunt, lnomr, lfrmr,linterp;
+
+ s = code;
+
+ lpunt -= 2;
+ lnomr -= 2;
+ lfrmr -= 2;
+ linterp -= 2;
+
+ modrm(OldwR, O(Frame, t), RFP, RAX); // MOVL t(FP), RAX
+ genw(OmovwRD|(DTMP<<9)|RAX);
+ genw(0x4A80|DTMP); // TSTL DTMP
+ genw(Ojeq|(uchar)(lpunt-(code-s))); // JEQ lpunt
+ modrm(OldwR, O(Type, destroy), RAX, RAX); // MOVL destroy(RAX), RAX
+ genw(OmovwRD|(DTMP<<9)|RAX);
+ genw(0x4A80|DTMP); // TSTL DTMP
+ genw(Ojeq|(uchar)(lpunt-(code-s))); // JEQ lpunt
+ modrm(OtstwR, O(Frame, fp), RFP, 0); // TSTL fp(RFP)
+ genw(Ojeq|(uchar)(lpunt-(code-s))); // JEQ lpunt
+ modrm(OtstwR, O(Frame, mr), RFP, 0); // TSTL mr(RFP)
+ genw(Ojeq|(uchar)(lnomr-(code-s))); // JEQ lnomr
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OldwR, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(OdecrwRind, O(Module, ref), RTA, 0); // DECL ref(RTA)
+ genw(Ojne|(uchar)(lfrmr-(code-s))); // JNE lfrmr
+ modrm(OincrwRind, O(Module, ref), RTA, 0); // INCL ref(RTA)
+ genw(Obra|(uchar)(lpunt-(code-s))); // JMP lpunt
+ lfrmr = code - s;
+ modrm(OldwR, O(Frame, mr), RFP, RTA); // MOVL mr(RFP), RTA
+ modrm(OstwR, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(OldwR, O(Modlink, MP), RTA, RMP); // MOVL mp(RTA), RMP
+ modrm(OstwR, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP
+
+ modrm(OtstwR, O(Modlink, compiled), RTA, 0); // CMPL $0, M.compiled
+ genw(Ojeq|(uchar)(linterp-(code-s)));
+
+ lnomr = code - s;
+ genw(OjsrRind|RAX); // CALL* AX
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OstwR, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(OldwR, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(OldwR, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ genw(OjmpRind|RAX); // JMP*L AX
+
+ linterp = code - s;
+ genw(OjsrRind|RAX); // CALL* AX
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OstwR, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(OldwR, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(OstwR, O(REG, PC), RTMP, RAX); // MOVL RAX, R.PC
+ modrm(OldwR, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+
+ genw(Orts);
+ lpunt = code - s; // label:
+ i.add = AXNON;
+ punt(&i, NEWPC, optab[IRET]);
+ if(pass&&(cflag > 2)) {
+ print("macret\n");
+ das(s, code-s);
+ }
+}
+
+static void
+maccolr(void)
+{
+ uchar *s;
+ s=code;
+ modrm(OincrwRind, O(Heap, ref)-sizeof(Heap), RTMP, 0); // INCL ref(RTMP)
+ genw(0x2079|(RAX<<9)); // MOVL (mutator), RAX
+ genl((ulong)&mutator);
+ modrm(OcmpwR, O(Heap, color)-sizeof(Heap), RTMP, RAX); // CMPL color(RTMP), RAX
+ genw(Ojne|0x02);
+ genw(Orts);
+ conR(propagator, RAX); // MOVL $propagator,RAX
+ modrm(OstwR, O(Heap, color)-sizeof(Heap), RTMP, RAX); // MOVL RAX, color(RTMP)
+ genw(0x23C8|RAX); // can be any !0 value
+ genl((ulong)&nprop); // MOVL RAX, (nprop)
+ genw(Orts);
+ if(pass&&(cflag > 2)) {
+ print("maccolr\n");
+ das(s, code-s);
+ }
+}
+
+static void
+macmcal(void)
+{
+ uchar *s,*label,*interp;
+ s=code;
+
+ genw(0x2040|(RCX<<9)|DTMP);
+ modrm(OtstwR,O(Module, prog),RCX,0); // TSTL ml->m->prog
+
+ genw(Ojne); // JNE patch
+ label = code-1;
+ modrm(OstwR, O(REG, FP), RTMP, RTA);
+ modrm(OstwR, O(REG, dt), RTMP, RAX);
+ // CALL rmcall
+ bra((ulong)rmcall, Obsr);
+
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OldwR, O(REG, FP), RTMP, RFP);
+ modrm(OldwR, O(REG, MP), RTMP, RMP);
+ genw(Orts); // RET
+ *label = code-label-1; // patch:
+ genw(0x2048|(RFP<<9)|RTA); // MOVL RTA, RFP R.FP = f
+ modrm(OstwR, O(REG, M), RTMP, RCX); // MOVL RCX, R.M
+ modrm(OincrwRind, O(Module, ref), RCX, 0); // INC.L R.M->ref
+ modrm(OldwR, O(Modlink, MP), RCX, RMP); // MOVL R.M->mp, RMP
+ modrm(OstwR, O(REG, MP), RTMP, RMP); // MOVL RCX, R.MP R.MP = ml->m
+ modrm(OtstwR, O(Module, compiled), RCX, 0);// CMPL $0, M.compiled
+
+ genw(OpopwR|(RCX<<9)); // balance call
+ genw(Ojeq); // JEQ interp
+ interp=code-1;
+ genw(OjmpRind|RAX); // JMP*L AX
+ *interp= code-interp-1;
+ modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ modrm(OstwR, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genw(Orts);
+ if(pass&&(cflag > 2)) {
+ print("macmcal\n");
+ das(s, code-s);
+ }
+}
+
+static void
+macfram(void)
+{
+ uchar *label,*s;
+ s=code;
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OldwD, O(REG, SP), RTMP, DTMP); // MOVL R.SP, DTMP
+ modrm(OaddRD, O(Type, size), RTA, DTMP);// ADDL size(RTA), DTMP
+ modrm(OcmpwD, O(REG, TS), RTMP, DTMP); // CMPL DTMP, R.TS
+ genw(Ojlt); // JLT .+(patch)
+ label = code-1;
+
+ modrm(OstwR, O(REG, s), RTMP, RTA);
+ modrm(OstwR, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ // BSR extend
+ bra((ulong)extend, Obsr);
+ conR((ulong)&R, RTMP);
+ modrm(OldwR, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(OldwR, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ modrm(OldwR, O(REG, s), RTMP, RAX); // MOVL R.s, *R.d
+ genw(Orts); // RET
+ *label = code-label-1;
+ modrm(OldwR, O(REG, SP), RTMP, RAX); // MOVL R.SP, RAX
+ modrm(OstwD, O(REG, SP), RTMP, DTMP); // MOVL DTMP, R.SP
+
+ modrm(OstwR, O(Frame, t), RAX, RTA); // MOVL RTA, t(RAX) f->t = t
+ genw(OmovwR|(RAX<<9)); // MOVL $0, mr(RAX) f->mr
+ genl(0);
+ genw(REGMOD*4);
+
+ modrm(OldwR, O(Type, initialize), RTA, RTA);
+ genw(OjmpRind|RTA); // JMP*L RTA
+ genw(Orts); // RET
+ if(pass&&(cflag > 2)) {
+ print("macfram\n");
+ das(s, code-s);
+ }
+}
+
+static void
+macmfra(void)
+{
+ uchar *s;
+ s=code;
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OstwR, O(REG, FP), RTMP, RFP);
+ modrm(OstwR, O(REG, s), RTMP, RAX); // Save type
+ modrm(OstwR, O(REG, d), RTMP, RTA); // Save destination
+ // CALL rmfram
+ bra((ulong)rmfram, Obsr);
+ conR((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(OldwR, O(REG, FP), RTMP, RFP);
+ modrm(OldwR, O(REG, MP), RTMP, RMP);
+ genw(Orts); // RET
+ if(pass&&(cflag > 2)) {
+ print("macmfra\n");
+ das(s, code-s);
+ }
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ modrm(OldwR, j, RFP, RAX);
+ rbra(macro[MacFRP], Obsr);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ genw(Orts);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ conD((ulong)H, DTMP);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ modrm(OstwD, j, RAX, DTMP);
+ j += sizeof(WORD*);
+ }
+ }
+ genw(Orts);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ uchar *tmp;
+ tmp=malloc(4096);
+
+ if(tmp == nil)
+ error(exNomem);
+ if(t == nil || t->initialize != 0)
+ return;
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(t->initialize, n);
+
+ if(cflag > 1) {
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+ if (cflag > 2)
+ das(t->destroy, code-(uchar*)t->destroy);
+ }
+ free(tmp);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ ulong v;
+ Link *l;
+ Modl *e;
+ int i, n;
+ uchar *s, *tmp;
+ base = nil;
+
+ tmp=malloc(4096);
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ if(code >= &tmp[4096]) {
+ print("tmp ovlo\n%3d %D\n", i, &m->prog[i]);
+ urk();
+ }
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ (*mactab[i].gen)();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ nlit *= sizeof(ulong);
+ base = mallocz(n + nlit, 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 1)
+ print("dis=%5d %5d 386=%5d asm=%.8p lit=%d: %s\n",
+ size, size*sizeof(Inst), n, base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = (ulong*)(base+n);
+ code = base;
+ n = 0;
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("phase error\n%3d %D\n", i, &m->prog[i]);
+ urk();
+ }
+ n += code - s;
+ if(cflag > 1) {
+ print("%d: %D\n", i,&m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ if(macro[mactab[i].idx] != n) {
+ print("phase error\nmactab %d\n", mactab[i].idx);
+ urk();
+ }
+ s = code;
+ (*mactab[i].gen)();
+ n += code-s;
+ if(cflag > 1) {
+ print("mactab %d\n", mactab[i].idx);
+ das(s, code-s);
+ }
+ }
+
+ v = (ulong)base;
+ for(l = m->ext; l->name; l++) {
+//print("### link: %lux ",l->u.pc-m->prog);
+ l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+//print("%lux\n",l->u.pc);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(v+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(tmp);
+ free(patch);
+ free(tinit);
+ free(base);
+ return 0;
+}
diff --git a/libinterp/comp-arm.c b/libinterp/comp-arm.c
new file mode 100644
index 00000000..a793c2c1
--- /dev/null
+++ b/libinterp/comp-arm.c
@@ -0,0 +1,2260 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * to do:
+ * eliminate litpool?
+ * eliminate long constants in comi/comd
+ * bounds checks
+ * enable and check inline FP code (not much point with fpemu)
+ */
+
+#define RESCHED 1 /* check for interpreter reschedule */
+
+enum
+{
+ R0 = 0,
+ R1 = 1,
+ R2 = 2,
+ R3 = 3,
+ R4 = 4,
+ R5 = 5,
+ R6 = 6,
+ R7 = 7,
+ R8 = 8,
+ R9 = 9,
+ R10 = 10,
+ R11 = 11,
+ R12 = 12, /* C's SB */
+ R13 = 13, /* C's SP */
+ R14 = 14, /* Link Register */
+ R15 = 15, /* PC */
+
+ RLINK = 14,
+
+ RFP = R9, /* Frame Pointer */
+ RMP = R8, /* Module Pointer */
+ RTA = R7, /* Intermediate address for double indirect */
+ RCON = R6, /* Constant builder */
+ RREG = R5, /* Pointer to REG */
+ RA3 = R4, /* gpr 3 */
+ RA2 = R3, /* gpr 2 2+3 = L */
+ RA1 = R2, /* gpr 1 */
+ RA0 = R1, /* gpr 0 0+1 = L */
+
+
+ FA2 = 2, /* Floating */
+ FA3 = 3,
+ FA4 = 4,
+ FA5 = 5,
+
+ EQ = 0,
+ NE = 1,
+ CS = 2,
+ CC = 3,
+ MI = 4,
+ PL = 5,
+ VS = 6,
+ VC = 7,
+ HI = 8,
+ LS = 9,
+ GE = 10,
+ LT = 11,
+ GT = 12,
+ LE = 13,
+ AL = 14,
+ NV = 15,
+
+ HS = CS,
+ LO = CC,
+
+ And = 0,
+ Eor = 1,
+ Sub = 2,
+ Rsb = 3,
+ Add = 4,
+ Adc = 5,
+ Sbc = 6,
+ Rsc = 7,
+ Tst = 8,
+ Teq = 9,
+ Cmp = 10,
+ Cmn = 11,
+ Orr = 12,
+ Mov = 13,
+ Bic = 14,
+ Mvn = 15,
+
+ Adf = 0,
+ Muf = 1,
+ Suf = 2,
+ Rsf = 3,
+ Dvf = 4,
+ Rdf = 5,
+ Rmf = 8,
+
+ Mvf = 0,
+ Mnf = 1,
+ Abs = 2,
+ Rnd = 3,
+
+ Flt = 0,
+ Fix = 1,
+
+ Cmf = 4,
+ Cnf = 5,
+
+ Lea = 100, /* macro memory ops */
+ Ldw,
+ Ldb,
+ Stw,
+ Stb,
+ Ldf,
+ Stf,
+ Ldh,
+
+ NCON = (0xFFC-8)/4,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET,
+ MacCASE,
+ MacCOLR,
+ MacMCAL,
+ MacFRAM,
+ MacMFRA,
+ MacRELQ,
+ NMACRO
+};
+
+#define BITS(B) (1<<B)
+#define IMM(O) (O & ((1<<12)-1))
+#define SBIT (1<<20)
+#define PBIT (1<<24)
+#define UPBIT (1<<23)
+
+#define LDW(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define STW(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define LDB(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define STB(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+
+#define LDxP(C, Rn, Rd, O, B) *code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define STxP(C, Rn, Rd, O, B) *code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define LDRW(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define STRW(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define LDRB(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define STRB(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+
+#define DPI(C, Op, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Op<<21)|\
+ (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define DP(C, Op, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Op<<21)|(Rn<<16)|\
+ (Rd<<12)|((Sh)<<4)|Ro
+#define CMPI(C, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Cmp<<21)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define CMNI(C, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Cmn<<21)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define CMP(C, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Cmp<<21)|(Rn<<16)|(1<<20)|\
+ (Rd<<12)|((Sh)<<4)|Ro
+#define CMN(C, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Cmn<<21)|(Rn<<16)|(1<<20)|\
+ (Rd<<12)|((Sh)<<4)|Ro
+#define MUL(C, Rm, Rs, Rd) *code++ = (C<<28)|(Rd<<16)|(Rm<<0)|(Rs<<8)|\
+ (9<<4)
+
+#define LDF(C, Rn, Fd, O) *code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
+#define STF(C, Rn, Fd, O) *code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|\
+ (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
+#define CMF(C, Fn, Fm) *code++ = (C<<28)|(7<<25)|(4<<21)|(1<<20)|(Fn<<16)|\
+ (0xF<<12)|(1<<8)|(1<<4)|(Fm)
+
+#define LDH(C, Rn, Rd, O) *code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(((O)&0xf0)<<4)|(0xb<<4)|((O)&0xf)
+#define LDRH(C, Rn, Rd, Rm) *code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(0xb<<4)|Rm
+
+#define CPDO2(C, Op, Fn, Fd, Fm) *code++ = (C<<28)|(0xE<<24)|(Op<<20)|(Fn<<16)|(Fd<<12)|(1<<8)|(1<<7)|(Fm)
+#define CPDO1(C, Op, Fd, Fm) CPDO2((C),(Op),0,(Fd),(Fm))|(1<<15)
+#define CPFLT(C, Fn, Rd) *code++ = (C<<28)|(0xE<<24)|(0<<20)|(Fn<<16)|(Rd<<12)|(1<<8)|(9<<4)
+#define CPFIX(C, Rd, Fm) *code++ = (C<<28)|(0xE<<24)|(1<<20)|(0<<16)|(Rd<<12)|(1<<8)|(9<<4)|(Fm)
+
+#define BRAW(C, o) ((C<<28)|(5<<25)|((o) & 0x00ffffff))
+#define BRA(C, o) gen(BRAW((C),(o)))
+#define IA(s, o) (ulong)(base+s[o])
+#define BRADIS(C, o) BRA(C, (IA(patch, o)-(ulong)code-8)>>2)
+#define BRAMAC(r, o) BRA(r, (IA(macro, o)-(ulong)code-8)>>2)
+#define BRANCH(C, o) gen(BRAW(C, ((ulong)(o)-(ulong)code-8)>>2))
+#define CALL(o) gen(BRAW(AL, ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
+#define CCALL(C,o) gen(BRAW((C), ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
+#define CALLMAC(C,o) gen(BRAW((C), (IA(macro, o)-(ulong)code-8)>>2)|(1<<24))
+#define RELPC(pc) (ulong)(base+(pc))
+#define RETURN DPI(AL, Add, RLINK, R15, 0, 0)
+#define CRETURN(C) DPI(C, Add, RLINK, R15, 0, 0)
+#define PATCH(ptr) *ptr |= (((ulong)code-(ulong)(ptr)-8)>>2) & 0x00ffffff
+
+#define MOV(src, dst) DP(AL, Mov, 0, dst, 0, src)
+#define FITS8(v) ((ulong)(v)<BITS(8))
+#define FITS5(v) ((ulong)(v)<BITS(5))
+
+/* assumes H==-1 */
+#define CMPH(C, r) CMNI(C, r, 0, 0, 1)
+#define NOTNIL(r) (CMPH(AL, (r)), CCALL(EQ, bounds))
+
+/* array bounds checking */
+#define BCK(r, rb) (CMP(AL, rb, 0, 0, r), CCALL(LS, bounds))
+#define BCKI(i, rb) (CMPI(AL, rb, 0, 0, i), CCALL(LS, bounds))
+
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static ulong codeoff;
+static int pass;
+static int puntpc = 1;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static void macrelq(void);
+static void movmem(Inst*);
+static void mid(Inst*, int, int);
+extern void das(ulong*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+ char* name;
+} mactab[] =
+{
+ MacFRP, macfrp, "FRP", /* decrement and free pointer */
+ MacRET, macret, "RET", /* return instruction */
+ MacCASE, maccase, "CASE", /* case instruction */
+ MacCOLR, maccolr, "COLR", /* increment and color pointer */
+ MacMCAL, macmcal, "MCAL", /* mcall bottom half */
+ MacFRAM, macfram, "FRAM", /* frame instruction */
+ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+typedef struct Const Const;
+struct Const
+{
+ ulong o;
+ ulong* code;
+ ulong* pc;
+};
+
+typedef struct Con Con;
+struct Con
+{
+ int ptr;
+ Const table[NCON];
+};
+static Con rcon;
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Frame *f;
+ Prog *p;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ if(R.d == H)
+ error(exModule);
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static void
+urk(char *s)
+{
+ USED(s);
+ error(exCompile); //production
+ //panic("compile failed: urk: %s\n", s); //debugging
+}
+
+static void
+gen(ulong w)
+{
+ *code++ = w;
+}
+
+static long
+immrot(ulong v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return (i<<8) | v | (1<<25);
+ v = (v<<2) | (v>>30);
+ }
+ return 0;
+}
+
+static long
+immaddr(long v)
+{
+
+ if(v >= 0 && v <= 0xfff)
+ return (v & 0xfff) |
+ (1<<24) | /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xfff && v < 0)
+ return (-v & 0xfff) |
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+static void
+flushcon(int genbr)
+{
+ int i;
+ Const *c;
+ ulong disp;
+
+ if(rcon.ptr == 0)
+ return;
+ if(genbr){
+ if(0)print("BR %d(PC)=%8.8p (len=%d)\n", (rcon.ptr*4+4-8)>>2, code+rcon.ptr+1, rcon.ptr);
+ BRA(AL, (rcon.ptr*4+4-8)>>2);
+ }
+ c = &rcon.table[0];
+ for(i = 0; i < rcon.ptr; i++) {
+ if(pass){
+ disp = (code - c->code) * sizeof(*code) - 8;
+ if(disp >= BITS(12))
+ print("INVALID constant range %lud", disp);
+ if(0)print("data %8.8p %8.8lux (%8.8p, ins=%8.8lux cpc=%8.8p)\n", code, c->o, c->code, *c->code, c->pc);
+ *c->code |= (disp&0xfff);
+ }
+ *code++ = c->o;
+ c++;
+ }
+ rcon.ptr = 0;
+}
+
+static void
+flushchk(void)
+{
+ if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(12)-256){ // 256 allows for a little delay in calling flushchk
+ if(0)print("flushed constant table: len %ux disp %ld\n", rcon.ptr, (code+codeoff-rcon.table[0].pc)*sizeof(*code)-8);
+ flushcon(1);
+ }
+}
+
+static void
+ccon(int cc, ulong o, int r, int opt)
+{
+ ulong u;
+ Const *c;
+
+ if(opt != 0) {
+ u = o & ~0xff;
+ if(u == 0) {
+ DPI(cc, Mov, 0, r, 0, o);
+ return;
+ }
+ if(u == ~0xff) {
+ DPI(cc, Mvn, 0, r, 0, ~o);
+ return;
+ }
+ u = immrot(o);
+ if(u) {
+ DPI(cc, Mov, 0, r, 0, 0) | u;
+ return;
+ }
+ u = o & ~0xffff;
+ if(u == 0) {
+ DPI(cc, Mov, 0, r, 0, o);
+ DPI(cc, Orr, r, r, (24/2), o>>8);
+ return;
+ }
+ }
+ flushchk();
+ c = &rcon.table[rcon.ptr++];
+ c->o = o;
+ c->code = code;
+ c->pc = code+codeoff;
+ LDW(cc, R15, r, 0);
+}
+
+static void
+memc(int c, int inst, ulong disp, int rm, int r)
+{
+ int bit;
+
+ if(inst == Lea) {
+ if(disp < BITS(8)) {
+ DPI(c, Add, rm, r, 0, disp);
+ return;
+ }
+ if(-disp < BITS(8)) {
+ DPI(c, Sub, rm, r, 0, -disp);
+ return;
+ }
+ bit = immrot(disp);
+ if(bit) {
+ DPI(c, Add, rm, r, 0, 0) | bit;
+ return;
+ }
+ ccon(c, disp, RCON, 1);
+ DP(c, Add, rm, r, 0, RCON);
+ return;
+ }
+
+ if(disp < BITS(12) || -disp < BITS(12)) { /* Direct load */
+ if(disp < BITS(12))
+ bit = 0;
+ else {
+ disp = -disp;
+ bit = UPBIT;
+ }
+ switch(inst) {
+ case Ldw:
+ LDW(c, rm, r, disp);
+ break;
+ case Ldb:
+ LDB(c, rm, r, disp);
+ break;
+ case Stw:
+ STW(c, rm, r, disp);
+ break;
+ case Stb:
+ STB(c, rm, r, disp);
+ break;
+ }
+ if(bit)
+ code[-1] ^= bit;
+ return;
+ }
+
+ ccon(c, disp, RCON, 1);
+ switch(inst) {
+ case Ldw:
+ LDRW(c, rm, r, 0, RCON);
+ break;
+ case Ldb:
+ LDRB(c, rm, r, 0, RCON);
+ break;
+ case Stw:
+ STRW(c, rm, r, 0, RCON);
+ break;
+ case Stb:
+ STRB(c, rm, r, 0, RCON);
+ break;
+ }
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+ ccon(AL, o, r, opt);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+ memc(AL, inst, disp, rm, r);
+}
+
+static void
+opx(int mode, Adr *a, int mi, int r, int li)
+{
+ int ir, rta;
+
+ switch(mode) {
+ default:
+ urk("opx");
+ case AFP:
+ mem(mi, a->ind, RFP, r);
+ return;
+ case AMP:
+ mem(mi, a->ind, RMP, r);
+ return;
+ case AIMM:
+ con(a->imm, r, 1);
+ if(mi == Lea) { /* could be simpler if con generates reachable literal */
+ mem(Stw, li, RREG, r);
+ mem(Lea, li, RREG, r);
+ }
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Lea)
+ rta = r;
+ mem(Ldw, a->i.f, ir, rta);
+ mem(mi, a->i.s, rta, r);
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+ opx(USRC(i->add), &i->s, op, reg, O(REG, st));
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+ opx(UDST(i->add), &i->d, op, reg, O(REG, dt));
+}
+
+static void
+memfl(int cc, int inst, ulong disp, int rm, int r)
+{
+ int bit, wd;
+
+ wd = (disp&03)==0;
+ bit = 0;
+ if(wd && disp < BITS(10))
+ disp >>= 2; /* direct load */
+ else if(wd && -disp < BITS(10)){
+ bit = UPBIT;
+ disp = -disp >> 2;
+ }else{
+ ccon(cc, disp, RCON, 1);
+ DP(cc, Add, RCON, RCON, 0, rm);
+ rm = RCON;
+ disp = 0;
+ }
+ switch(inst) {
+ case Ldf:
+ LDF(cc, rm, r, disp);
+ break;
+ case Stf:
+ STF(cc, rm, r, disp);
+ break;
+ }
+ if(bit)
+ code[-1] ^= bit;
+}
+
+static void
+opfl(Adr *a, int am, int mi, int r)
+{
+ int ir;
+
+ switch(am) {
+ default:
+ urk("opfl");
+ case AFP:
+ memfl(AL, mi, a->ind, RFP, r);
+ return;
+ case AMP:
+ memfl(AL, mi, a->ind, RMP, r);
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ mem(Ldw, a->i.f, ir, RTA);
+ memfl(AL, mi, a->i.s, RTA, r);
+}
+
+static void
+opflld(Inst *i, int mi, int r)
+{
+ opfl(&i->s, USRC(i->add), mi, r);
+}
+
+static void
+opflst(Inst *i, int mi, int r)
+{
+ opfl(&i->d, UDST(i->add), mi, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ con((ulong)litpool, RTA, 0);
+ mem(Stw, roff, RREG, RTA);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ if(RESCHED && i->d.ins <= i){
+ mem(Ldw, O(REG, IC), RREG, RA0);
+ DPI(AL, Sub, RA0, RA0, 0, 1) | SBIT;
+ mem(Stw, O(REG, IC), RREG, RA0);
+ /* CMPI(AL, RA0, 0, 0, 1); */
+ CALLMAC(LE, MacRELQ);
+ }
+}
+
+static void
+bounds(void)
+{
+ /* mem(Stw, O(REG,FP), RREG, RFP); */
+ error(exBounds);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Lea, RA0);
+ mem(Stw, O(REG, s), RREG, RA0);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Lea, RA0);
+ mem(Stw, O(REG, d), RREG, RA0);
+ }
+ if(m & WRTPC) {
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Stw, O(REG, PC), RREG, RA0);
+ }
+ if(m & DBRAN) {
+ pc = patch[i->d.ins-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ mem(Ldw, O(REG, d), RREG, RA0);
+ mem(Stw, O(REG, m), RREG, RA0);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG,m));
+ break;
+ case AXINF:
+ mem(Lea, i->reg, RFP, RA2);
+ mem(Stw, O(REG, m), RREG, RA2);
+ break;
+ case AXINM:
+ mem(Lea, i->reg, RMP, RA2);
+ mem(Stw, O(REG, m), RREG, RA2);
+ break;
+ }
+ mem(Stw, O(REG, FP), RREG, RFP);
+
+ CALL(fn);
+
+ con((ulong)&R, RREG, 1);
+ if(m & TCHECK) {
+ mem(Ldw, O(REG, t), RREG, RA0);
+ CMPI(AL, RA0, 0, 0, 0);
+ memc(NE, Ldw, O(REG, xpc), RREG, RLINK);
+ CRETURN(NE); /* if(R.t) goto(R.xpc) */
+ }
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+
+ if(m & NEWPC){
+ mem(Ldw, O(REG, PC), RREG, R15);
+ flushcon(0);
+ }
+}
+
+static void
+midfl(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opflst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1); // BUG
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ memfl(AL, mi, i->reg, ir, r);
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ if(mi == Lea)
+ urk("mid/lea");
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case GE:
+ return LE;
+ case LE:
+ return GE;
+ case GT:
+ return LT;
+ case LT:
+ return GT;
+ }
+ return b;
+}
+
+static void
+cbra(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) {
+ mid(i, Ldw, RA1);
+ CMPI(AL, RA1, 0, 0, i->s.imm);
+ r = swapbraop(r);
+ } else if(UXSRC(i->add) == SRC(AIMM) && FITS8(-i->s.imm)) {
+ mid(i, Ldw, RA1);
+ CMNI(AL, RA1, 0, 0, -i->s.imm);
+ r = swapbraop(r);
+ } else if((i->add & ARM) == AXIMM && FITS8(i->reg)) {
+ opwld(i, Ldw, RA1);
+ CMPI(AL, RA1, 0, 0, i->reg);
+ } else if((i->add & ARM) == AXIMM && FITS8(-(short)i->reg)) {
+ opwld(i, Ldw, RA1);
+ CMNI(AL, RA1, 0, 0, -(short)i->reg);
+ } else {
+ opwld(i, Ldw, RA0);
+ mid(i, Ldw, RA1);
+ CMP(AL, RA0, 0, 0, RA1);
+ }
+ BRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbrab(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ mid(i, Ldb, RA1);
+ CMPI(AL, RA1, 0, 0, i->s.imm&0xFF);
+ r = swapbraop(r);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Ldb, RA1);
+ CMPI(AL, RA1, 0, 0, i->reg&0xFF);
+ } else {
+ opwld(i, Ldb, RA0);
+ mid(i, Ldb, RA1);
+ CMP(AL, RA0, 0, 0, RA1);
+ }
+ BRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst, *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Lea, RA1);
+ mid(i, Lea, RA3);
+ mem(Ldw, 0, RA1, RA2);
+ mem(Ldw, 0, RA3, RA0);
+ CMP(AL, RA2, 0, 0, RA0);
+ label = nil;
+ dst = i->d.ins-mod->prog;
+ switch(mode) {
+ case ANDAND:
+ label = code;
+ BRA(jmsw, 0);
+ break;
+ case OROR:
+ BRADIS(jmsw, dst);
+ break;
+ case EQAND:
+ BRADIS(jmsw, dst);
+ label = code;
+ BRA(NE, 0);
+ break;
+ }
+ mem(Ldw, 4, RA3, RA0);
+ mem(Ldw, 4, RA1, RA2);
+ CMP(AL, RA2, 0, 0, RA0);
+ BRADIS(jlsw, dst);
+ if(label != nil)
+ PATCH(label);
+}
+
+static void
+cbraf(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(0){
+ ulong *s=code;
+ opflld(i, Ldf, FA4);
+ midfl(i, Ldf, FA2);
+ CMF(AL, FA4, FA2);
+ BRADIS(r, i->d.ins-mod->prog);
+ if(pass){print("%D\n", i); das(s, code-s);}
+ }else
+ punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Ldw, RA1); // v
+ opwst(i, Lea, RA3); // table
+ BRAMAC(AL, MacCASE);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = RELPC(patch[t[2]]);
+ t += 3;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = RELPC(patch[t[4]]);
+ t += 6;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+ ulong *punt, *mlnil;
+
+ opwld(i, Ldw, RA0);
+ CMPH(AL, RA0);
+ mlnil = code;
+ BRA(EQ, 0);
+
+ if((i->add&ARM) == AXIMM) {
+ mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3);
+ } else {
+ mid(i, Ldw, RA1);
+ DP(AL, Add, RA0, RA1, (3<<3), RA1); // assumes sizeof(Modl) == 8
+ mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, RA3);
+ }
+
+ mem(Ldw, O(Type, initialize), RA3, RA1);
+ CMPI(AL, RA1, 0, 0, 0);
+ punt = code;
+ BRA(NE, 0);
+
+ opwst(i, Lea, RA0);
+
+ /* Type in RA3, destination in RA0 */
+ PATCH(mlnil);
+ con(RELPC(patch[i-mod->prog+1]), RLINK, 0);
+ BRAMAC(AL, MacMFRA);
+
+ /* Type in RA3 */
+ PATCH(punt);
+ CALLMAC(AL, MacFRAM);
+ opwst(i, Stw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+ ulong *mlnil;
+
+ opwld(i, Ldw, RA2);
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Stw, O(Frame, lr), RA2, RA0);
+ mem(Stw, O(Frame, fp), RA2, RFP);
+ mem(Ldw, O(REG, M), RREG, RA3);
+ mem(Stw, O(Frame, mr), RA2, RA3);
+ opwst(i, Ldw, RA3);
+ CMPH(AL, RA3);
+ mlnil = code;
+ BRA(EQ, 0);
+ if((i->add&ARM) == AXIMM) {
+ mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+ } else {
+ mid(i, Ldw, RA1);
+ DP(AL, Add, RA3, RA1, (3<<3), RA1); // assumes sizeof(Modl) == 8
+ mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0);
+ }
+ PATCH(mlnil);
+ CALLMAC(AL, MacMCAL);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Lea, RA0);
+ mid(i, Lea, RA3);
+ mem(Ldw, 4, RA0, RA1); // ls (big endian `big' even in little endian mode)
+ mem(Ldw, 4, RA3, RA2);
+ DP(AL, op, RA2, RA2, 0, RA1) | SBIT; // ls: RA2 = RA2 op RA1
+ mem(Ldw, 0, RA0, RA1);
+ mem(Ldw, 0, RA3, RA0);
+ DP(AL, opc, RA0, RA0, 0, RA1); // ms: RA0 = RA0 opc RA1
+ if((i->add&ARM) != AXNON)
+ opwst(i, Lea, RA3);
+ mem(Stw, 0, RA3, RA0);
+ mem(Stw, 4, RA3, RA2);
+}
+
+static void
+movloop(Inst *i, int s)
+{
+ int b;
+
+ b = (s==1);
+ opwst(i, Lea, RA2);
+ LDxP(AL, RA1, RA0, s, b);
+ STxP(AL, RA2, RA0, s, b);
+ DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
+ BRA(NE, (-3*4-8)>>2);
+}
+
+static void
+movmem(Inst *i)
+{
+ ulong *cp;
+
+ // source address already in RA1
+ if((i->add&ARM) != AXIMM){
+ mid(i, Ldw, RA3);
+ CMPI(AL, RA3, 0, 0, 0);
+ cp = code;
+ BRA(LE, 0);
+ movloop(i, 1);
+ PATCH(cp);
+ return;
+ }
+ switch(i->reg){
+ case 0:
+ break;
+ case 4:
+ LDW(AL, RA1, RA2, 0);
+ opwst(i, Stw, RA2);
+ break;
+ case 8:
+ LDW(AL, RA1, RA2, 0);
+ opwst(i, Lea, RA3);
+ LDW(AL, RA1, RA1, 4);
+ STW(AL, RA3, RA2, 0);
+ STW(AL, RA3, RA1, 4);
+ break;
+ default:
+ // could use ldm/stm loop...
+ if((i->reg&3) == 0) {
+ con(i->reg>>2, RA3, 1);
+ movloop(i, 4);
+ } else {
+ con(i->reg, RA3, 1);
+ movloop(i, 1);
+ }
+ break;
+ }
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ opwld(i, Ldw, RA1);
+ opwst(i, Lea, RA0);
+ LDRW(AL, RA0, R15, (2<<3), RA1);
+ flushcon(0);
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = RELPC(patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comp(Inst *i)
+{
+ int r, imm;
+ char buf[64];
+//ulong *s = code;
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ puntpc = 0;
+ punt(&xx, SRCOP, compdbg);
+ puntpc = 1;
+ flushcon(1);
+ }
+ flushchk();
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ case IMODW:
+ case IMODB:
+ case IDIVW:
+ case IDIVB:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADB:
+ case IHEADW:
+ case IHEADL:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IMOVF:
+ if(0){
+ opflld(i, Ldf, FA2);
+ opflst(i, Stf, FA2);
+ break;
+ }
+ /* if no hardware, just fall through */
+ case IMOVL:
+ opwld(i, Lea, RA1);
+ LDW(AL, RA1, RA2, 0);
+ LDW(AL, RA1, RA3, 4);
+ opwst(i, Lea, RA1);
+ STW(AL, RA1, RA2, 0);
+ STW(AL, RA1, RA3, 4);
+ break;
+ break;
+ case IHEADM:
+ opwld(i, Ldw, RA1);
+ NOTNIL(RA1);
+ DPI(AL, Add, RA1, RA1, 0, OA(List,data));
+ movmem(i);
+ break;
+/*
+ case IHEADW:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0);
+ mem(Ldw, OA(List, data), RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+*/
+ case IMOVM:
+ opwld(i, Lea, RA1);
+ movmem(i);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RA3, 1);
+ CALL(base+macro[MacFRAM]);
+ opwst(i, Stw, RA2);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Ldb, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case ICVTWB:
+ opwld(i, Ldw, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case ILEA:
+ opwld(i, Lea, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMOVW:
+ opwld(i, Ldw, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMOVB:
+ opwld(i, Ldb, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case ITAIL:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0);
+ mem(Ldw, O(List, tail), RA0, RA1);
+ goto movp;
+ case IMOVP:
+ opwld(i, Ldw, RA1);
+ goto movp;
+ case IHEADP:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0);
+ mem(Ldw, OA(List, data), RA0, RA1);
+ movp:
+ CMPH(AL, RA1);
+ CALLMAC(NE, MacCOLR); // colour if not H
+ opwst(i, Lea, RA2);
+ mem(Ldw, 0,RA2, RA0);
+ mem(Stw, 0,RA2, RA1);
+ CALLMAC(AL, MacFRP);
+ break;
+ case ILENA:
+ opwld(i, Ldw, RA1);
+ con(0, RA0, 1);
+ CMPH(AL, RA1);
+ LDW(NE, RA1, RA0, O(Array,len));
+ opwst(i, Stw, RA0);
+ break;
+ case ILENC:
+ opwld(i, Ldw, RA1);
+ con(0, RA0, 1);
+ CMPH(AL, RA1);
+ memc(NE, Ldw, O(String,len),RA1, RA0);
+ CMPI(AL, RA0, 0, 0, 0);
+ DPI(LT, Rsb, RA0, RA0, 0, 0);
+ opwst(i, Stw, RA0);
+ break;
+ case ILENL:
+ con(0, RA0, 1);
+ opwld(i, Ldw, RA1);
+
+ CMPH(AL, RA1);
+ LDW(NE, RA1, RA1, O(List, tail));
+ DPI(NE, Add, RA0, RA0, 0, 1);
+ BRA(NE, (-4*3-8)>>2);
+
+ opwst(i, Stw, RA0);
+ break;
+ case ICALL:
+ opwld(i, Ldw, RA0);
+ con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+ mem(Stw, O(Frame, lr), RA0, RA1);
+ mem(Stw, O(Frame, fp), RA0, RFP);
+ MOV(RA0, RFP);
+ BRADIS(AL, i->d.ins-mod->prog);
+ flushcon(0);
+ break;
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ BRADIS(AL, i->d.ins-mod->prog);
+ flushcon(0);
+ break;
+ case IBEQW:
+ cbra(i, EQ);
+ break;
+ case IBNEW:
+ cbra(i, NE);
+ break;
+ case IBLTW:
+ cbra(i, LT);
+ break;
+ case IBLEW:
+ cbra(i, LE);
+ break;
+ case IBGTW:
+ cbra(i, GT);
+ break;
+ case IBGEW:
+ cbra(i, GE);
+ break;
+ case IBEQB:
+ cbrab(i, EQ);
+ break;
+ case IBNEB:
+ cbrab(i, NE);
+ break;
+ case IBLTB:
+ cbrab(i, LT);
+ break;
+ case IBLEB:
+ cbrab(i, LE);
+ break;
+ case IBGTB:
+ cbrab(i, GT);
+ break;
+ case IBGEB:
+ cbrab(i, GE);
+ break;
+ case IBEQF:
+ cbraf(i, EQ);
+ break;
+ case IBNEF:
+ cbraf(i, NE);
+ break;
+ case IBLTF:
+ cbraf(i, LT);
+ break;
+ case IBLEF:
+ cbraf(i, LE);
+ break;
+ case IBGTF:
+ cbraf(i, GT);
+ break;
+ case IBGEF:
+ cbraf(i, GE);
+ break;
+ case IRET:
+ mem(Ldw, O(Frame,t), RFP, RA1);
+ BRAMAC(AL, MacRET);
+ break;
+ case IMULW:
+ opwld(i, Ldw, RA1);
+ mid(i, Ldw, RA0);
+ MUL(AL, RA1, RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMULB:
+ opwld(i, Ldb, RA1);
+ mid(i, Ldb, RA0);
+ MUL(AL, RA1, RA0, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case IORW:
+ r = Orr;
+ goto arithw;
+ case IANDW:
+ r = And;
+ goto arithw;
+ case IXORW:
+ r = Eor;
+ goto arithw;
+ case ISUBW:
+ r = Sub;
+ goto arithw;
+ case IADDW:
+ r = Add;
+ arithw:
+ mid(i, Ldw, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm))
+ DPI(AL, r, RA1, RA0, 0, i->s.imm);
+ else if(UXSRC(i->add) == SRC(AIMM) && immrot(i->s.imm)){
+ DPI(AL, r, RA1, RA0, 0, 0) | immrot(i->s.imm);
+ //print("rot: %ux %ux\n", i->s.imm, immrot(i->s.imm)); das(code-1, 1);
+ } else {
+ opwld(i, Ldw, RA0);
+ DP(AL, r, RA1, RA0, 0, RA0);
+ }
+ opwst(i, Stw, RA0);
+ break;
+ case ISHRW:
+ r = 2;
+ shiftw:
+ mid(i, Ldw, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
+ DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
+ else {
+ opwld(i, Ldw, RA0);
+ DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
+ }
+ opwst(i, Stw, RA0);
+ break;
+ case ISHLW:
+ r = 0;
+ goto shiftw;
+ break;
+ case IORB:
+ r = Orr;
+ goto arithb;
+ case IANDB:
+ r = And;
+ goto arithb;
+ case IXORB:
+ r = Eor;
+ goto arithb;
+ case ISUBB:
+ r = Sub;
+ goto arithb;
+ case IADDB:
+ r = Add;
+ arithb:
+ mid(i, Ldb, RA1);
+ if(UXSRC(i->add) == SRC(AIMM))
+ DPI(AL, r, RA1, RA0, 0, i->s.imm);
+ else {
+ opwld(i, Ldb, RA0);
+ DP(AL, r, RA1, RA0, 0, RA0);
+ }
+ opwst(i, Stb, RA0);
+ break;
+ case ISHRB:
+ r = 2;
+ goto shiftb;
+ case ISHLB:
+ r = 0;
+ shiftb:
+ mid(i, Ldb, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
+ DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
+ else {
+ opwld(i, Ldw, RA0);
+ DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
+ }
+ opwst(i, Stb, RA0);
+ break;
+ case IINDC:
+ opwld(i, Ldw, RA1); // RA1 = string
+ NOTNIL(RA1);
+ imm = 1;
+ if((i->add&ARM) != AXIMM || !FITS8((short)i->reg<<1)){
+ mid(i, Ldw, RA2); // RA2 = i
+ imm = 0;
+ }
+ mem(Ldw, O(String,len),RA1, RA0); // len<0 => index Runes, otherwise bytes
+ DPI(AL, Add, RA1, RA1, 0, O(String,data));
+ CMPI(AL, RA0, 0, 0, 0);
+ if(bflag)
+ DPI(LT, Rsb, RA0, RA0, 0, 0);
+ if(imm){
+ LDB(GE, RA1, RA3, i->reg);
+ LDH(LT, RA1, RA3, (short)i->reg<<1);
+ if(bflag)
+ BCKI(i->reg, RA0);
+ } else {
+ LDRB(GE, RA1, RA3, 0, RA2);
+ DP(LT, Mov, 0, RA2, (1<<3), RA2);
+ LDRH(LT, RA1, RA3, RA2);
+ if(bflag)
+ BCK(RA2, RA0);
+ }
+ opwst(i, Stw, RA3);
+ break;
+ case IINDL:
+ case IINDF:
+ case IINDW:
+ case IINDB:
+ opwld(i, Ldw, RA0); /* a */
+ NOTNIL(RA0);
+ mem(Ldw, O(Array, data), RA0, RA0);
+ if(bflag)
+ mem(Ldw, O(Array, len), RA0, RA2);
+ r = 0;
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ r = 3;
+ break;
+ case IINDW:
+ r = 2;
+ break;
+ }
+ if(UXDST(i->add) == DST(AIMM) && FITS8(i->d.imm<<r)) {
+ if(bflag)
+ BCKI(i->d.imm, RA2);
+ DPI(AL, Add, RA0, RA0, 0, (i->d.imm<<r));
+ } else {
+ opwst(i, Ldw, RA1);
+ if(bflag)
+ BCK(RA1, RA2);
+ DP(AL, Add, RA0, RA0, r<<3, RA1);
+ }
+ mid(i, Stw, RA0);
+ break;
+ case IINDX:
+ opwld(i, Ldw, RA0); /* a */
+ NOTNIL(RA0);
+ opwst(i, Ldw, RA1); /* i */
+
+ if(bflag){
+ mem(Ldw, O(Array, len), RA0, RA2);
+ BCK(RA1, RA2);
+ }
+ mem(Ldw, O(Array, t), RA0, RA2);
+ mem(Ldw, O(Array, data), RA0, RA0);
+ mem(Ldw, O(Type, size), RA2, RA2);
+ MUL(AL, RA2, RA1, RA1);
+ DP(AL, Add, RA1, RA0, 0, RA0);
+ mid(i, Stw, RA0);
+ break;
+ case IADDL:
+ larith(i, Add, Adc);
+ break;
+ case ISUBL:
+ larith(i, Sub, Sbc);
+ break;
+ case IORL:
+ larith(i, Orr, Orr);
+ break;
+ case IANDL:
+ larith(i, And, And);
+ break;
+ case IXORL:
+ larith(i, Eor, Eor);
+ break;
+ case ICVTWL:
+ opwld(i, Ldw, RA1);
+ opwst(i, Lea, RA2);
+ DP(AL, Mov, 0, RA0, (0<<3)|(2<<1), RA1); // ASR 32
+ STW(AL, RA2, RA0, 0);
+ STW(AL, RA2, RA1, 4);
+ break;
+ case ICVTLW:
+ opwld(i, Lea, RA0);
+ mem(Ldw, 4, RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IBEQL:
+ cbral(i, NE, EQ, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, NE, NE, OROR);
+ break;
+ case IBLEL:
+ cbral(i, LT, LS, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, GT, HI, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, LT, CC, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, GT, CS, EQAND);
+ break;
+ case ICVTFL:
+ case ICVTLF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case IDIVF:
+ r = Dvf;
+ goto arithf;
+ case IMULF:
+ r = Muf;
+ goto arithf;
+ case ISUBF:
+ r = Suf;
+ goto arithf;
+ case IADDF:
+ r = Adf;
+ arithf:
+ if(1){
+ /* software fp */
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ }
+ opflld(i, Ldf, FA2);
+ midfl(i, Ldf, FA4);
+ CPDO2(AL, r, FA4, FA4, FA2);
+ opflst(i, Stf, FA4);
+ break;
+ case INEGF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opflld(i, Ldf, FA2);
+ CPDO1(AL, Mnf, FA2, FA2);
+ opflst(i, Stf, FA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case ICVTWF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Ldw, RA2);
+ CPFLT(AL, FA2, RA2);
+ opflst(i, Stf, FA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case ICVTFW:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opflld(i, Ldf, FA2);
+ CPFIX(AL, RA2, FA2);
+ opwst(i, Stw, RA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case ISHLL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISHRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(10 * sizeof(*code));
+ if(comvec == nil)
+ error(exNomem);
+ code = (ulong*)comvec;
+
+ con((ulong)&R, RREG, 0);
+ mem(Stw, O(REG, xpc), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ mem(Ldw, O(REG, PC), RREG, R15);
+ pass++;
+ flushcon(0);
+ pass--;
+
+ segflush(comvec, 10 * sizeof(*code));
+}
+
+static void
+maccase(void)
+{
+ ulong *cp1, *loop, *inner;
+/*
+ * RA1 = value (input arg), t
+ * RA2 = count, n
+ * RA3 = table pointer (input arg)
+ * RA0 = n/2, n2
+ * RCON = pivot element t+n/2*3, l
+ */
+ LDW(AL, RA3, RA2, 0); // count from table
+ MOV(RA3, RLINK); // initial table pointer
+
+ loop = code; // loop:
+ CMPI(AL, RA2, 0, 0, 0);
+ cp1 = code;
+ BRA(LE, 0); // n <= 0? goto out
+
+ inner = code;
+ DP(AL, Mov, 0, RA0, (1<<3)|2, RA2); // n2 = n>>1
+ DP(AL, Add, RA0, RCON, (1<<3), RA0); // n' = n2+(n2<<1) = 3*n2
+ DP(AL, Add, RA3, RCON, (2<<3), RCON); // l = t + n2*3;
+
+ LDW(AL, RCON, RTA, 4);
+ CMP(AL, RA1, 0, 0, RTA);
+ DP(LT, Mov, 0, RA2, 0, RA0); // v < l[1]? n=n2
+ BRANCH(LT, loop); // v < l[1]? goto loop
+
+ LDW(AL, RCON, RTA, 8);
+ CMP(AL, RA1, 0, 0, RTA);
+ LDW(LT, RCON, R15, 12); // v >= l[1] && v < l[2] => found; goto l[3]
+
+ // v >= l[2] (high)
+ DPI(AL, Add, RCON, RA3, 0, 12); // t = l+3;
+ DPI(AL, Add, RA0, RTA, 0, 1);
+ DP(AL, Sub, RA2, RA2, 0, RTA) | SBIT; // n -= n2+1
+ BRANCH(GT, inner); // n > 0? goto loop
+
+ PATCH(cp1); // out:
+ LDW(AL, RLINK, RA2, 0); // initial n
+ DP(AL, Add, RA2, RA2, (1<<3), RA2); // n = n+(n<<1) = 3*n
+ DP(AL, Add, RLINK, RLINK, (2<<3), RA2); // t' = &(initial t)[n*3]
+ LDW(AL, RLINK, R15, 4); // goto (initial t)[n*3+1]
+}
+
+static void
+macfrp(void)
+{
+ /* destroy the pointer in RA0 */
+ CMPH(AL, RA0);
+ CRETURN(EQ); // arg == H? => return
+
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ DPI(AL, Sub, RA2, RA2, 0, 1) | SBIT;
+ memc(NE, Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ CRETURN(NE); // --h->ref != 0 => return
+
+ mem(Stw, O(REG, FP), RREG, RFP);
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, s), RREG, RA0);
+ CALL(rdestroy);
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ flushcon(0);
+}
+
+static void
+maccolr(void)
+{
+ /* color the pointer in RA1 */
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ DPI(AL, Add, RA0, RA0, 0, 1);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0); // h->ref++
+ con((ulong)&mutator, RA2, 1);
+ mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+ mem(Ldw, 0, RA2, RA2);
+ CMP(AL, RA0, 0, 0, RA2);
+ CRETURN(EQ); // return if h->color == mutator
+ con(propagator, RA2, 1);
+ mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2); // h->color = propagator
+ con((ulong)&nprop, RA2, 1);
+ mem(Stw, 0, RA2, RA2); // nprop = !0
+ RETURN;
+ flushcon(0);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+
+ CMPI(AL, RA1, 0, 0, 0);
+ cp1 = code;
+ BRA(EQ, 0); // t(Rfp) == 0
+
+ mem(Ldw, O(Type,destroy),RA1, RA0);
+ CMPI(AL, RA0, 0, 0, 0);
+ cp2 = code;
+ BRA(EQ, 0); // destroy(t(fp)) == 0
+
+ mem(Ldw, O(Frame,fp),RFP, RA2);
+ CMPI(AL, RA2, 0, 0, 0);
+ cp3 = code;
+ BRA(EQ, 0); // fp(Rfp) == 0
+
+ mem(Ldw, O(Frame,mr),RFP, RA3);
+ CMPI(AL, RA3, 0, 0, 0);
+ cp4 = code;
+ BRA(EQ, 0); // mr(Rfp) == 0
+
+ mem(Ldw, O(REG,M),RREG, RA2);
+ mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+ DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
+ cp5 = code;
+ BRA(EQ, 0); // --ref(arg) == 0
+ mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+ mem(Ldw, O(Frame,mr),RFP, RA1);
+ mem(Stw, O(REG,M),RREG, RA1);
+ mem(Ldw, O(Modlink,MP),RA1, RMP);
+ mem(Stw, O(REG,MP),RREG, RMP);
+ mem(Ldw, O(Modlink,compiled), RA1, RA3); // R.M->compiled
+ CMPI(AL, RA3, 0, 0, 0);
+ linterp = code;
+ BRA(EQ, 0);
+
+ PATCH(cp4);
+ MOV(R15, R14); // call destroy(t(fp))
+ MOV(RA0, R15);
+
+ mem(Stw, O(REG,SP),RREG, RFP);
+ mem(Ldw, O(Frame,lr),RFP, RA1);
+ mem(Ldw, O(Frame,fp),RFP, RFP);
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ DP(AL, Mov, 0, R15, 0, RA1); // goto lr(Rfp), if compiled
+
+ PATCH(linterp);
+ MOV(R15, R14); // call destroy(t(fp))
+ MOV(RA0, R15);
+
+ mem(Stw, O(REG,SP),RREG, RFP);
+ mem(Ldw, O(Frame,lr),RFP, RA1);
+ mem(Ldw, O(Frame,fp),RFP, RFP);
+ mem(Stw, O(REG,PC),RREG, RA1); // R.PC = fp->lr
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; // return to xec uncompiled code
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macmcal(void)
+{
+ ulong *lab;
+
+ CMPH(AL, RA0);
+ memc(NE, Ldw, O(Modlink, prog), RA3, RA1); // RA0 != H
+ CMPI(NE, RA1, 0, 0, 0); // RA0 != H
+ lab = code;
+ BRA(NE, 0); // RA0 != H && m->prog!=0
+
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, FP), RREG, RA2);
+ mem(Stw, O(REG, dt), RREG, RA0);
+ CALL(rmcall); // CALL rmcall
+
+ con((ulong)&R, RREG, 1); // MOVL $R, RREG
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+
+ PATCH(lab); // patch:
+ DP(AL, Mov, 0, RFP, 0, RA2);
+ mem(Stw, O(REG, M), RREG, RA3); // MOVL RA3, R.M
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ DPI(AL, Add, RA1, RA1, 0, 1);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ mem(Ldw, O(Modlink, MP), RA3, RMP); // MOVL R.M->mp, RMP
+ mem(Stw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->m
+ mem(Ldw, O(Modlink,compiled), RA3, RA1); // M.compiled?
+ CMPI(AL, RA1, 0, 0, 0);
+ DP(NE, Mov, 0, R15, 0, RA0); // return to compiled code
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Stw, O(REG,PC),RREG, RA0); // R.PC = RPC
+ mem(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; // return to xec uncompiled code
+ flushcon(0);
+}
+
+static void
+macfram(void)
+{
+ ulong *lab1;
+
+ mem(Ldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0
+ mem(Ldw, O(Type, size), RA3, RA1);
+ DP(AL, Add, RA0, RA0, 0, RA1); // nsp = R.SP + t->size
+ mem(Ldw, O(REG, TS), RREG, RA1);
+ CMP(AL, RA0, 0, 0, RA1); // nsp :: R.TS
+ lab1 = code;
+ BRA(CS, 0); // nsp >= R.TS; must expand
+
+ mem(Ldw, O(REG, SP), RREG, RA2); // MOVL R.SP, RA2
+ mem(Stw, O(REG, SP), RREG, RA0); // MOVL RA0, R.SP
+
+ mem(Stw, O(Frame, t), RA2, RA3); // MOVL RA3, t(RA2) f->t = t
+ con(0, RA0, 1);
+ mem(Stw, O(Frame,mr), RA2, RA0); // MOVL $0, mr(RA2) f->mr
+ mem(Ldw, O(Type, initialize), RA3, R15); // become t->init(RA2), returning RA2
+
+ PATCH(lab1);
+ mem(Stw, O(REG, s), RREG, RA3);
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP
+ CALL(extend); // CALL extend
+
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP); // MOVL R.FP, RFP
+ mem(Ldw, O(REG, s), RREG, RA2); // MOVL R.s, *R.d
+ mem(Ldw, O(REG, MP), RREG, RMP); // MOVL R.MP, RMP
+ RETURN; // RET
+}
+
+static void
+macmfra(void)
+{
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, s), RREG, RA3); // Save type
+ mem(Stw, O(REG, d), RREG, RA0); // Save destination
+ mem(Stw, O(REG, FP), RREG, RFP);
+ CALL(rmfram); // CALL rmfram
+
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+}
+
+static void
+macrelq(void)
+{
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Stw, O(REG,PC),RREG, RLINK); // R.PC = RLINK
+ mem(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN;
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mem(Stw, O(REG, dt), RREG, RLINK);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ mem(Ldw, j, RFP, RA0);
+ CALL(base+macro[MacFRP]);
+ }
+ j += sizeof(WORD*);
+ }
+ flushchk();
+ }
+ mem(Ldw, O(REG, dt), RREG, RLINK);
+ RETURN;
+ flushcon(0);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RA0, 1);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Stw, j, RA2, RA0);
+ j += sizeof(WORD*);
+ }
+ flushchk();
+ }
+ RETURN;
+ flushcon(0);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 3)
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+extern ulong timer_start(void);
+extern ulong timer_ticks(ulong);
+extern ulong tmr2ms(ulong);
+extern ulong tmr2us(ulong);
+extern void timer_delay();
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = malloc(4096*sizeof(ulong));
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ codeoff = n;
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ codeoff = n;
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+ code = tmp;
+ flushcon(0);
+ n += code - tmp;
+
+ base = mallocz((n+nlit)*sizeof(*code), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d 386=%5d asm=%.8p: %s\n",
+ size, size*sizeof(Inst), n, base, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+ n = 0;
+ codeoff = 0;
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ print("%lud != %d\n", patch[i], n);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 4) {
+ print("%3d %D\n", i, &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ s = code;
+ mactab[i].gen();
+ if(macro[mactab[i].idx] != n){
+ print("mac phase err: %lud != %d\n", macro[mactab[i].idx], n);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 4) {
+ print("%s:\n", mactab[i].name);
+ das(s, code-s);
+ }
+ }
+ s = code;
+ flushcon(0);
+ n += code - s;
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(base);
+ free(tmp);
+ return 0;
+}
diff --git a/libinterp/comp-mips.c b/libinterp/comp-mips.c
new file mode 100644
index 00000000..ef812500
--- /dev/null
+++ b/libinterp/comp-mips.c
@@ -0,0 +1,1955 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define T(r) *((void**)(R.r))
+
+#define SRR(op,c,r1,r2) gen((op)|((c)<<6)|((r1)<<16)|((r2)<<11))
+#define RRR(op,r1,r2,r3) gen((op)|((r1)<<16)|((r2)<<21)|((r3)<<11))
+#define FRRR(op,r1,r2,r3) gen((op)|((r1)<<16)|((r2)<<11)|((r3)<<6))
+#define FI(op,c) gen((op)|((c)&0xffff))
+#define IRR(op,c,r1,r2) gen((op)|((c)&0xffff)|((r1)<<21)|((r2)<<16))
+#define BRRI(op,r1,r2,c) gen((op)|((r1)<<21)|((r2)<<16)|((c)&0xffff))
+#define BRI(op,r,c) gen((op)|((r)<<21)|((c)&0xffff))
+#define JR(op,r) gen((op)|((r)<<21))
+#define J(op,c) gen((op)|(((ulong)(c)>>2)&0x3FFFFFFUL))
+
+enum
+{
+ Rzero = 0,
+
+ Ro1 = 8,
+ Ro2 = 9,
+ Ro3 = 10,
+ Ri = 11,
+ Rj = 12,
+
+ Rmp = 13,
+ Rfp = 14,
+ Rreg = 15,
+
+ Rpic = 25,
+ Rlink = 31,
+
+ Rf1 = 4,
+ Rf2 = 6,
+
+ Olw = 0x23<<26,
+ Olbu = 0x24<<26,
+ Olhu = 0x25<<26,
+ Osw = 0x2b<<26,
+ Osb = 0x28<<26,
+ Oaddui = 0x09<<26,
+ Olui = 0x0f<<26,
+ Oori = 0x0d<<26,
+ Odiv = (0x00<<26) | 0x1a,
+ Omul = (0x00<<26) | 0x18,
+ Omfhi = (0x00<<26) | 0x10,
+ Omflo = (0x00<<26) | 0x12,
+ Osubu = (0x00<<26) | 0x23,
+ Oaddu = (0x00<<26) | 0x21,
+ Oand = (0x00<<26) | 0x24,
+ Oor = (0x00<<26) | 0x25,
+ Oxor = (0x00<<26) | 0x26,
+ Odelay = (0x00<<26) | 0x27,
+ Osll = (0x00<<26) | 0x00,
+ Osrl = (0x00<<26) | 0x02,
+ Osra = (0x00<<26) | 0x03,
+ Osllv = (0x00<<26) | 0x04,
+ Osrlv = (0x00<<26) | 0x06,
+ Osrav = (0x00<<26) | 0x07,
+ Oslt = (0x00<<26) | 0x2a,
+ Osltu = (0x00<<26) | 0x2b,
+ Obeq = 0x04<<26,
+ Obne = 0x05<<26,
+ Obltz = (0x01<<26) | (0x0<<16),
+ Obgtz = (0x07<<26) | (0x0<<16),
+ Oblez = (0x06<<26) | (0x0<<16),
+ Obgez = (0x01<<26) | (0x1<<16),
+ Ojr = (0x00<<26) | 0x08,
+ Ojalr = (0x00<<26) | 0x09 | (Rlink<<11),
+ Oj = (0x02<<26),
+ Ojal = (0x03<<26),
+ Olea = Oaddui, // pseudo op
+
+ Olf = 0x31<<26,
+ Osf = 0x39<<26,
+ Oaddf = (0x11<<26) | (17<<21) | 0,
+ Osubf = (0x11<<26) | (17<<21) | 1,
+ Omulf = (0x11<<26) | (17<<21) | 2,
+ Odivf = (0x11<<26) | (17<<21) | 3,
+ Onegf = (0x11<<26) | (17<<21) | 7,
+
+ Ocvtwf = (0x11<<26) | (20<<21) | 33,
+ Ocvtfw = (0x11<<26) | (17<<21) | 36,
+
+ Ofeq = (0x11<<26) | (17<<21) | (3<<4) | 2,
+ Oflt = (0x11<<26) | (17<<21) | (3<<4) | 12,
+
+ Obrf = (0x11<<26) | (0x100<<16),
+ Obrt = (0x11<<26) | (0x101<<16),
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR,
+ EQAND,
+
+ XOR,
+ IOR,
+ AND,
+ ADD,
+ SUB,
+
+ OMASK = (1<<4) - 1,
+ REV1 = 1<<4,
+ REV2 = 1<<5,
+
+ MacRET = 0,
+ MacFRP,
+ MacINDX,
+ MacCASE,
+ MacLENA,
+ MacFRAM,
+ MacMOVM,
+ MacCOLR,
+ MacMCAL,
+ MacMFRA,
+ MacEND,
+ NMACRO
+};
+
+extern char Tmodule[];
+ void (*comvec)(void);
+extern void das(ulong*);
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static int regdelay;
+static Module* mod;
+static ulong* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+static void rdestroy(void);
+static void macret(void);
+static void macfrp(void);
+static void macindx(void);
+static void maccase(void);
+static void maclena(void);
+static void macfram(void);
+static void macmovm(void);
+static void maccvtfw(void);
+static void maccolr(void);
+static void macend(void);
+static void macmcal(void);
+static void macmfra(void);
+
+struct
+{
+ int o;
+ void (*f)(void);
+} macinit[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacFRAM, macfram, /* frame instruction */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacMOVM, macmovm,
+ MacLENA, maclena,
+ MacINDX, macindx,
+ MacEND, macend,
+ 0
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+void
+urk(char *s)
+{
+ print("urk: %s\n", s);
+ exits(0);
+}
+
+void
+gen(ulong o)
+{
+ *code++ = o;
+}
+
+void
+delay(void)
+{
+ gen(Odelay);
+}
+
+int
+bigc(long c)
+{
+ c >>= 15;
+ if(c == 0 || c == -1)
+ return 0;
+ return 1;
+}
+
+void
+ldbigc(ulong c, int reg)
+{
+ IRR(Olui, c>>16,Rzero,reg);
+ IRR(Oori, c,reg,reg);
+}
+
+void
+ldc(ulong c, int reg)
+{
+
+ if(bigc(c))
+ ldbigc(c, reg);
+ else
+ IRR(Oaddui, c,Rzero, reg);
+}
+
+void
+xchg(void)
+{
+ ulong t;
+
+ t = code[-1];
+ code[-1] = code[-2];
+ code[-2] = t;
+}
+
+void
+opx(int mode, Adr *a, int op, int reg, int del)
+{
+ ulong c;
+ int r, rx;
+
+ switch(mode) {
+ case AFP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 1");
+ if(regdelay == Rfp)
+ delay();
+ IRR(op, c,Rfp, reg);
+ break;
+ case AMP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 2");
+ if(regdelay == Rmp)
+ delay();
+ IRR(op, c,Rmp, reg);
+ break;
+ case AIMM:
+ if(op == Olea) {
+ if(a->imm != 0) {
+ ldc(a->imm, reg);
+ IRR(Osw, O(REG,st),Rreg, reg);
+ } else
+ IRR(Osw, O(REG,st),Rreg, Rzero);
+ IRR(Oaddui, O(REG,st),Rreg, reg);
+ } else
+ ldc(a->imm, reg);
+ return;
+ case AIND|AFP:
+ r = Rfp;
+ goto offset;
+ case AIND|AMP:
+ r = Rmp;
+ offset:
+ if(regdelay == r)
+ delay();
+ c = a->i.s;
+ rx = Ri;
+ if(op == Olea || op == Olw)
+ rx = reg;
+ IRR(Olw, a->i.f,r, rx);
+ if(c != 0 || op != Oaddui) {
+ delay();
+ IRR(op, c,rx, reg);
+ }
+ break;
+ }
+ if(op != Olea && del)
+ delay();
+ regdelay = 0;
+}
+
+void
+op1(Inst *i, int op, int reg, int del)
+{
+ opx(USRC(i->add), &i->s, op, reg, del);
+}
+
+void
+op3(Inst *i, int op, int reg, int del)
+{
+ opx(UDST(i->add), &i->d, op, reg, del);
+}
+
+void
+op2(Inst *i, int op, int reg, int del)
+{
+ switch(i->add & ARM) {
+ case AXNON:
+ op3(i, op, reg, del);
+ return;
+ case AXIMM:
+ if(op == Olea) {
+ if((short)i->reg != 0) {
+ ldc((short)i->reg, reg);
+ IRR(Osw, O(REG,t),Rreg, reg);
+ } else
+ IRR(Osw, O(REG,t),Rreg, Rzero);
+ IRR(Oaddui, O(REG,t),Rreg, reg);
+ } else
+ ldc((short)i->reg, reg);
+ return;
+ case AXINF:
+ IRR(op, i->reg,Rfp, reg);
+ break;
+ case AXINM:
+ IRR(op, i->reg,Rmp, reg);
+ break;
+ }
+ if(op != Olea && del)
+ delay();
+}
+
+ulong
+branch(Inst *i)
+{
+ ulong rel;
+
+ if(base == 0)
+ return 0;
+ rel = patch[(Inst*)i->d.imm - mod->prog];
+ rel += (base - code) - 1;
+ return rel & 0xffff;
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ ldbigc((ulong)litpool, Ro1);
+ IRR(Osw, roff, Rreg, Ro1);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong *cp, pc;
+
+ if(m & SRCOP) {
+ op1(i, Olea, Ro1, 1);
+ IRR(Osw, O(REG,s),Rreg, Ro1);
+ }
+ if(m & DSTOP) {
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, O(REG,d),Rreg, Ro3);
+ }
+ if(m & WRTPC) {
+ pc = patch[i-mod->prog+1];
+ ldbigc((ulong)(base+pc), Ro1);
+ IRR(Osw, O(REG,PC),Rreg, Ro1);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ if((i->add&ARM) == AXNON) {
+ if(m & THREOP) {
+ delay();
+ IRR(Olw, O(REG,d),Rreg, Ro2);
+ delay();
+ IRR(Osw, O(REG,m),Rreg, Ro2);
+ }
+ } else {
+ op2(i, Olea, Ro2, 1);
+ IRR(Osw, O(REG,m),Rreg, Ro2);
+ }
+
+ ldc((ulong)fn, Rpic);
+ JR(Ojalr, Rpic);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ regdelay = Rmp;
+
+ if(m & TCHECK) {
+ IRR(Olw, O(REG,t),Rreg, Ro1);
+ xchg();
+ cp = code;
+ BRRI(Obeq,Ro1,Rzero,0);
+ IRR(Olw, O(REG,xpc),Rreg, Ro2);
+ delay();
+ JR(Ojr, Ro2);
+ delay();
+ *cp |= (code - cp) - 1;
+ regdelay = 0;
+ }
+
+ if(m & NEWPC) {
+ IRR(Olw, O(REG,PC),Rreg, Ro1);
+ if(m & TCHECK)
+ delay();
+ else
+ xchg();
+ JR(Ojr, Ro1);
+ delay();
+ regdelay = 0;
+ }
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ op1(i, Olw, Ro2, 0);
+ op3(i, Olea, Ro3, 0);
+ SRR(Osll, 2, Ro2, Ro2);
+ RRR(Oaddu, Ro2, Ro3, Ro3);
+ IRR(Olw, 0,Ro3, Ro1);
+ delay();
+ JR(Ojr, Ro1);
+ delay();
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)(base + patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ op1(i, Olw, Ro1, 0); // v
+ op3(i, Olea, Ro3, 0); // table
+ J(Oj, base+macro[MacCASE]);
+ xchg();
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)(base + patch[t[2]]);
+ t += 3;
+ }
+ t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ Modlink *ml;
+ ulong *cp1, *cp2;
+
+ op1(i, Olw, Ro1, 0);
+ ldc((ulong)H, Ri);
+ cp1 = code;
+ BRRI(Obeq, Ro1,Ri, 0);
+ delay();
+
+ ml = nil;
+ IRR(Olw, (ulong)&ml->links[i->reg].frame,Ro1, Ri);
+ delay();
+ IRR(Olw, O(Type,initialize),Ri, Ro2);
+ delay();
+ cp2 = code;
+ BRRI(Obne, Ro2,Rzero, 0);
+ delay();
+
+ op3(i, Olea, Rj, 0);
+
+ *cp1 |= (code - cp1) - 1;
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Rlink);
+ J(Oj, base+macro[MacMFRA]);
+ xchg();
+
+ *cp2 |= (code - cp2) - 1;
+ J(Ojal, base+macro[MacFRAM]);
+ delay();
+ op3(i, Osw, Ro1, 0);
+}
+
+static void
+commcall(Inst *i)
+{
+ Modlink *ml;
+
+ op1(i, Olw, Ro1, 0); // f in Ro1
+ IRR(Olw, O(REG,M),Rreg, Ro3);
+ IRR(Osw, O(Frame,fp),Ro1, Rfp); // f->fp = R.FP
+ IRR(Osw, O(Frame,mr),Ro1, Ro3); // f->mr = R.M
+ op3(i, Olw, Ri, 1);
+ ml = nil;
+ IRR(Olw, (ulong)&ml->links[i->reg].u.pc,Ri, Rj);// ml->entry in Rj
+ J(Ojal, base+macro[MacMCAL]);
+ xchg();
+}
+
+static void
+cbral(Inst *i, int op, int mode)
+{
+ ulong *cp;
+
+ cp = 0;
+ op1(i, Olea, Ri, 0);
+ op2(i, Olea, Rj, 0);
+ IRR(Olw, 0,Ri, Ro1);
+ IRR(Olw, 0,Rj, Ro2);
+ IRR(Olw, 4,Ri, Ri);
+
+ switch(mode & OMASK) {
+ case ANDAND:
+ cp = code;
+ BRRI(Obne, Ro2,Ro1, 0);
+ goto b1;
+
+ case OROR:
+ BRRI(Obne, Ro2,Ro1, branch(i));
+ b1:
+ IRR(Olw, 4,Rj, Rj);
+ delay();
+ BRRI(op, Rj,Ri, branch(i));
+ break;
+
+ case EQAND:
+ if(mode & REV1)
+ RRR(Oslt, Ro2,Ro1, Ro3);
+ else
+ RRR(Oslt, Ro1,Ro2, Ro3);
+ BRI(Obne, Ro3, branch(i));
+ IRR(Olw, 4,Rj, Rj);
+ cp = code;
+ BRRI(Obne, Ro2,Ro1, 0);
+ if(mode & REV2)
+ RRR(Osltu, Rj,Ri, Ro3);
+ else
+ RRR(Osltu, Ri,Rj, Ro3);
+ BRI(op, Ro3, branch(i));
+ break;
+ }
+ delay();
+ if(cp)
+ *cp |= (code - cp) - 1;
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+ int o1, o2;
+
+ o1 = Olw;
+ if(b1flag)
+ o1 = Olbu;
+ o2 = Olw;
+ if(b2flag)
+ o2 = Olbu;
+ if((i->add & ARM) == AXIMM) {
+ op1(i, o1, Ro1, 0);
+ op2(i, o2, Ro2, 1);
+ } else {
+ op2(i, o2, Ro2, 0);
+ op1(i, o1, Ro1, 1);
+ }
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+ op1(i, o1, Ro1, 1);
+ op3(i, o2, Ro1, 0);
+}
+
+static void
+shrl(Inst *i)
+{
+ int c;
+
+ if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+ }
+ c = i->s.imm;
+ op2(i, Olea, Ro3, 1);
+ IRR(Olw, 0,Ro3, Ro1);
+ if(c >= 32) {
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, 0);
+ else
+ delay();
+ SRR(Osra, 31, Ro1, Ro2);
+ IRR(Osw, 0,Ro3, Ro2);
+ if(c >= 64) {
+ IRR(Osw, 4,Ro3, Ro2);
+ return;
+ }
+ if(c > 32)
+ SRR(Osra, c-32, Ro1, Ro1);
+ IRR(Osw, 4,Ro3, Ro1);
+ return;
+ }
+ IRR(Olw, 4,Ro3, Ro2);
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, !c);
+ if(c != 0) {
+ SRR(Osll, 32-c, Ro1, Ri);
+ SRR(Osra, c, Ro1, Ro1);
+ SRR(Osrl, c, Ro2, Ro2);
+ RRR(Oor, Ri, Ro2, Ro2);
+ }
+ IRR(Osw, 4,Ro3, Ro2);
+ IRR(Osw, 0,Ro3, Ro1);
+}
+
+static void
+shll(Inst *i)
+{
+ int c;
+
+ if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+ }
+ c = i->s.imm;
+ if(c >= 64) {
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, 0,Ro3, Rzero);
+ IRR(Osw, 4,Ro3, Rzero);
+ return;
+ }
+ op2(i, Olea, Ro3, 1);
+ if(c >= 32) {
+ IRR(Olw, 4,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, 4,Ro3, Rzero);
+ if(c > 32)
+ SRR(Osll, c-32, Ro1, Ro1);
+ IRR(Osw, 0,Ro3, Ro1);
+ return;
+ }
+ IRR(Olw, 4,Ro3, Ro2);
+ IRR(Olw, 0,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, !c);
+ if(c != 0) {
+ SRR(Osrl, 32-c, Ro2, Ri);
+ SRR(Osll, c, Ro2, Ro2);
+ SRR(Osll, c, Ro1, Ro1);
+ RRR(Oor, Ri, Ro1, Ro1);
+ }
+ IRR(Osw, 4,Ro3, Ro2);
+ IRR(Osw, 0,Ro3, Ro1);
+}
+
+static void
+compdbg(void)
+{
+ print("%s:%d@%.8ux\n", R.M->m->name, R.t, R.st);
+}
+
+static void
+comp(Inst *i)
+{
+ int o, q, b;
+ ulong *cp, *cp1;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case ILSRL:
+ case IMNEWZ:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADL:
+ case IHEADMP:
+ case IINDC:
+ case ILENC:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTCL:
+ case ICVTLC:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTFL:
+ case ICVTLF:
+ case ICVTFR:
+ case ICVTRF:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTWB:
+ op13(i, Olw, Osb);
+ break;
+ case ICVTBW:
+ op13(i, Olbu, Osw);
+ break;
+ case ICVTWS:
+ op13(i, Olw, Osb);
+ break;
+ case ICVTSW:
+ op13(i, Olhu, Osw);
+ break;
+ case IMOVB:
+ op13(i, Olbu, Osb);
+ break;
+ case IMOVW:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ op3(i, Osw, Rzero, 0);
+ break;
+ }
+ op13(i, Olw, Osw);
+ break;
+ case ICVTLW:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olw, 4,Ro1, Ro1);
+ delay();
+ op3(i, Osw, Ro1, 0);
+ break;
+ case ICVTWL:
+ op1(i, Olw, Ro1, 0);
+ op3(i, Olea, Ro2, 0);
+ SRR(Osra, 31, Ro1, Ro3);
+ IRR(Osw, 4,Ro2, Ro1);
+ IRR(Osw, 0,Ro2, Ro3);
+ break;
+ case IHEADM:
+ op1(i, Olw, Ro1, 1);
+ IRR(Oaddui, OA(List,data),Ro1, Ro1);
+ goto m1;
+ case IMOVM:
+ op1(i, Olea, Ro1, 0);
+ m1:
+ op2(i, Olw, Ro2, 0);
+ op3(i, Olea, Ro3, 0);
+ J(Ojal, base+macro[MacMOVM]);
+ xchg();
+ break;
+ case IRET:
+ J(Oj, base+macro[MacRET]);
+ delay();
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ ldc((ulong)mod->type[i->s.imm], Ri);
+ J(Ojal, base+macro[MacFRAM]);
+ xchg();
+ op3(i, Osw, Ro1, 0);
+ tinit[i->s.imm] = 1;
+ break;
+ case ILEA:
+ op13(i, Olea, Osw);
+ break;
+ case IHEADW:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, OA(List,data),Ro1, Ro1);
+ delay();
+ op3(i, Osw, Ro1, 0);
+ break;
+ case IHEADF:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, OA(List,data),Ro1, Ro2);
+ IRR(Olw, OA(List,data)+4,Ro1, Ro3);
+ op3(i, Olea, Ro1, 1);
+ IRR(Osw, 0,Ro1, Ro2);
+ IRR(Osw, 4,Ro1, Ro3);
+ break;
+ case IHEADB:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olbu , OA(List,data),Ro1, Ro1);
+ delay();
+ op3(i, Osb, Ro1, 0);
+ break;
+ case ITAIL:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, O(List,tail),Ro1, Ro1);
+ goto movp;
+ case IMOVP:
+ op1(i, Olw, Ro1, 0);
+ goto movp;
+ case IHEADP:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, OA(List,data),Ro1, Ro1);
+ movp:
+ ldc((ulong)H, Ro2);
+ cp = code;
+ BRRI(Obeq,Ro1,Ro2,0);
+ ldbigc((ulong)&mutator, Ri);
+ J(Ojal, base+macro[MacCOLR]);
+ xchg();
+ *cp |= (code - cp) - 1;
+ op3(i, Olea, Ro3, 1);
+ IRR(Olw, 0,Ro3, Ri);
+ J(Ojal, base+macro[MacFRP]);
+ IRR(Osw, 0,Ro3, Ro1);
+ break;
+ case ILENA:
+ op1(i, Olw, Ri, 0);
+ J(Ojal, base+macro[MacLENA]);
+ xchg();
+ op3(i, Osw, Ro1, 0);
+ break;
+ case ILENL:
+ op1(i, Olw, Ro1, 0);
+ ldc((ulong)H, Ro2);
+ cp = code;
+ BRRI(Obeq, Ro1,Ro2, 0);
+ ldc(0, Ro3);
+
+ cp1 = code;
+ IRR(Olw, O(List,tail),Ro1, Ro1);
+ IRR(Oaddui, 1,Ro3, Ro3);
+ BRRI(Obne, Ro1,Ro2, (cp1-code)-1);
+ delay();
+
+ *cp |= (code - cp) - 1;
+ op3(i, Osw, Ro3, 0);
+ break;
+ case IMOVL:
+ case IMOVF:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olw, 0,Ro1, Ro2);
+ IRR(Olw, 4,Ro1, Ro3);
+ op3(i, Olea, Ro1, 1);
+ IRR(Osw, 0,Ro1, Ro2);
+ IRR(Osw, 4,Ro1, Ro3);
+ break;
+ case ICVTFW:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olf, 0,Ro1, Rf2+1);
+ IRR(Olf, 4,Ro1, Rf2);
+ delay();
+ FRRR(Ocvtfw, 0, Rf2, Rf2);
+ op3(i, Olea, Ro2, 1);
+ IRR(Osf, 0,Ro2, Rf2);
+ break;
+ case ICVTWF:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olf, 0,Ro1, Rf2);
+ delay();
+ FRRR(Ocvtwf, 0, Rf2, Rf2);
+ op3(i, Olea, Ro2, 1);
+ IRR(Osf, 0,Ro2, Rf2+1);
+ IRR(Osf, 4,Ro2, Rf2);
+ break;
+ case INEGF:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olf, 0,Ro1, Rf1+1);
+ IRR(Olf, 4,Ro1, Rf1);
+ op3(i, Olea, Ro2, 1);
+ FRRR(Onegf, 0, Rf1,Rf2);
+ IRR(Osf, 0,Ro2, Rf2+1);
+ IRR(Osf, 4,Ro2, Rf2);
+ break;
+ case IXORL:
+ case IORL:
+ case IANDL:
+ case IADDL:
+ case ISUBL:
+ op1(i, Olea, Ro1, 0);
+ op2(i, Olea, Ro3, 0);
+
+ IRR(Olw, 4,Ro1, Rj); /* ls */
+ IRR(Olw, 4,Ro3, Ro2);
+ IRR(Olw, 0,Ro1, Ri); /* ms */
+ IRR(Olw, 0,Ro3, Ro1);
+
+ switch(i->op) {
+ case IXORL:
+ o = Oxor;
+ goto l1;
+ case IORL:
+ o = Oor;
+ goto l1;
+ case IANDL:
+ o = Oand;
+ l1:
+ RRR(o, Ri,Ro1, Ro1);
+ RRR(o, Rj,Ro2, Ro2);
+ break;
+ case IADDL:
+ RRR(Oaddu, Ri,Ro1, Ro1);
+ RRR(Oaddu, Rj,Ro2, Ro2);
+ RRR(Osltu, Rj,Ro2, Ri);
+ RRR(Oaddu, Ri,Ro1, Ro1);
+ break;
+ case ISUBL:
+ RRR(Osubu, Ri,Ro1, Ro1);
+ RRR(Osltu, Rj,Ro2, Ri);
+ RRR(Osubu, Rj,Ro2, Ro2);
+ RRR(Osubu, Ri,Ro1, Ro1);
+ break;
+ }
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, 0,Ro3, Ro1);
+ IRR(Osw, 4,Ro3, Ro2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IADDF:
+ case ISUBF:
+ case IMULF:
+ case IDIVF:
+ case IBEQF:
+ case IBGEF:
+ case IBGTF:
+ case IBLEF:
+ case IBLTF:
+ case IBNEF:
+ op1(i, Olea, Ro1, 0);
+ op2(i, Olea, Ro2, 0);
+ IRR(Olf, 0,Ro1, Rf1+1);
+ IRR(Olf, 4,Ro1, Rf1);
+ IRR(Olf, 0,Ro2, Rf2+1);
+ IRR(Olf, 4,Ro2, Rf2);
+ switch(i->op) {
+ case IADDF: o = Oaddf; goto f1;
+ case ISUBF: o = Osubf; goto f1;
+ case IMULF: o = Omulf; goto f1;
+ case IDIVF: o = Odivf; goto f1;
+ case IBEQF: o = Ofeq; q = Obrt; goto f2;
+ case IBGEF: o = Oflt; q = Obrf; goto f3;
+ case IBGTF: o = Oflt; q = Obrt; goto f2;
+ case IBLEF: o = Oflt; q = Obrf; goto f2;
+ case IBLTF: o = Oflt; q = Obrt; goto f3;
+ case IBNEF: o = Ofeq; q = Obrf; goto f2;
+ f1:
+ op3(i, Olea, Ro1, 0);
+ FRRR(o, Rf1,Rf2, Rf2);
+ IRR(Osf, 0,Ro1, Rf2+1);
+ IRR(Osf, 4,Ro1, Rf2);
+ break;
+ f2:
+ delay();
+ FRRR(o, Rf1,Rf2, 0);
+ goto f4;
+ f3:
+ delay();
+ FRRR(o, Rf2,Rf1, 0);
+ goto f4;
+ f4:
+ delay();
+ FI(q, branch(i));
+ delay();
+ break;
+ }
+ break;
+
+ case IBLTB:
+ case IBLEB:
+ case IBGTB:
+ case IBGEB:
+ case IBEQB:
+ case IBNEB:
+ b = 1;
+ goto s1;
+ case IBLTW:
+ case IBLEW:
+ case IBGTW:
+ case IBGEW:
+ case IBEQW:
+ case IBNEW:
+ b = 0;
+ s1:
+ op12(i, b, b);
+ switch(i->op) {
+ case IBLTB:
+ case IBLTW: o = Obne; goto b1;
+ case IBGEB:
+ case IBGEW: o = Obeq; goto b1;
+ case IBGTB:
+ case IBGTW: o = Obne; goto b2;
+ case IBLEB:
+ case IBLEW: o = Obeq; goto b2;
+ case IBEQB:
+ case IBEQW: o = Obeq; goto b3;
+ case IBNEB:
+ case IBNEW: o = Obne; goto b3;
+ b1: RRR(Oslt, Ro2,Ro1, Ro3);
+ BRI(o,Ro3, branch(i));
+ break;
+ b2: RRR(Oslt, Ro1,Ro2, Ro3);
+ BRI(o,Ro3, branch(i));
+ break;
+ b3: BRRI(o, Ro2,Ro1, branch(i));
+ break;
+ }
+ delay();
+ break;
+
+ case IBEQL:
+ cbral(i, Obeq, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Obeq, EQAND|REV1);
+ break;
+ case IBGTL:
+ cbral(i, Obne, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Obne, EQAND|REV1|REV2);
+ break;
+ case IBGEL:
+ cbral(i, Obeq, EQAND|REV2);
+ break;
+
+ case ISUBB:
+ case IADDB:
+ case IANDB:
+ case IORB:
+ case IXORB:
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ b = 1;
+ op12(i, b, b);
+ goto s2;
+ case ISHLB:
+ case ISHRB:
+ b = 1;
+ op12(i, 0, b);
+ goto s2;
+ case ISUBW:
+ case IADDW:
+ case IANDW:
+ case IORW:
+ case IXORW:
+ case ISHLW:
+ case ISHRW:
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ b = 0;
+ op12(i, b, b);
+ s2:
+ switch(i->op) {
+ case IADDB:
+ case IADDW: o = Oaddu; goto c1;
+ case ISUBB:
+ case ISUBW: o = Osubu; goto c1;
+ case IANDB:
+ case IANDW: o = Oand; goto c1;
+ case IORB:
+ case IORW: o = Oor; goto c1;
+ case IXORB:
+ case IXORW: o = Oxor; goto c1;
+ c1:
+ RRR(o, Ro1,Ro2, Ro3);
+ break;
+ case ISHLB:
+ case ISHLW: o = Osllv; goto c2;
+ case ILSRW: o = Osrlv; goto c2;
+ case ISHRB:
+ case ISHRW: o = Osrav; goto c2;
+ c2:
+ RRR(o, Ro2,Ro1, Ro3);
+ break;
+ case IMULB:
+ case IMULW: q = Omul; o = Omflo; goto c3;
+ case IDIVB:
+ case IDIVW: q = Odiv; o = Omflo; goto c3;
+ case IMODB:
+ case IMODW: q = Odiv; o = Omfhi; goto c3;
+ c3:
+ RRR(q, Ro1,Ro2, Rzero);
+ RRR(o, Rzero,Rzero, Ro3);
+ break;
+ }
+ op3(i, b? Osb: Osw, Ro3, 0);
+ break;
+ case ICALL:
+ op1(i, Olw, Ro1, 0);
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2);
+ IRR(Osw, O(Frame,lr),Ro1, Ro2);
+ IRR(Osw, O(Frame,fp),Ro1, Rfp);
+ J(Oj, base+patch[(Inst*)i->d.imm - mod->prog]);
+ RRR(Oaddu, Ro1,Rzero, Rfp);
+ break;
+ case IJMP:
+ J(Oj, base+patch[(Inst*)i->d.imm - mod->prog]);
+ delay();
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IINDX:
+ op1(i, Olw, Ro1, 0); /* Ro1 = a */
+ op3(i, Olw, Ro3, 0); /* Ro2 = i */
+ J(Ojal, base+macro[MacINDX]);
+ xchg();
+ op2(i, Osw, Ro2, 0);
+ break;
+ case IINDB:
+ case IINDF:
+ case IINDW:
+ case IINDL:
+ op1(i, Olw, Ro1, 0); /* Ro1 = a */
+ op3(i, Olw, Ro3, 0); /* Ro3 = i */
+ IRR(Olw, O(Array,data),Ro1, Ro1); /* Ro1 = a->data */
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ SRR(Osll, 3, Ro3, Ro3); /* Ro3 = i*8 */
+ break;
+ case IINDW:
+ SRR(Osll, 2, Ro3, Ro3); /* Ro3 = i*4 */
+ break;
+ case IINDB:
+ delay();
+ break;
+ }
+ RRR(Oaddu, Ro1,Ro3, Ro2); /* Ro2 = i*size + data */
+ op2(i, Osw, Ro2, 0);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,PC),Rreg, Ri);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ IRR(Osw, O(REG,xpc),Rreg, Rlink);
+ JR(Ojr, Ri);
+ delay();
+}
+
+static void
+macfrp(void)
+{
+ ulong *cp1, *cp2;
+
+ ldc((ulong)H, Ro1);
+ cp1 = code;
+ BRRI(Obeq, Ri,Ro1, 0); // arg == $H
+ delay();
+
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+ ldc((ulong)1, Ro1);
+ cp2 = code;
+ BRRI(Obeq, Ro1,Ro2, 0); // ref(arg) == $1
+ IRR(Oaddui, -1,Ro2, Ro2); // ref(arg)--
+ JR(Ojr, Rlink);
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+
+ *cp2 |= (code - cp2) - 1;
+ IRR(Osw, O(REG,st),Rreg, Rlink);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+
+ ldc((ulong)rdestroy, Rpic);
+ JR(Ojalr, Rpic); // CALL destroy
+ IRR(Osw, O(REG,s),Rreg, Ri);
+
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+
+ *cp1 |= (code - cp1) - 1;
+ JR(Ojr, Rlink);
+ delay();
+}
+
+static void
+macret(void)
+{
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+ Inst i;
+
+// NOTE this needs to be scheduled
+
+ IRR(Olw, O(Frame,t),Rfp, Ro1);
+ delay();
+ cp1 = code;
+ BRRI(Obeq, Ro1,Rzero, 0); // t(Rfp) == 0
+ delay();
+
+ IRR(Olw, O(Type,destroy),Ro1, Rpic);
+ delay();
+ cp2 = code;
+ BRRI(Obeq, Rpic,Rzero, 0); // destroy(t(fp)) == 0
+ delay();
+
+ IRR(Olw, O(Frame,fp),Rfp, Ro2);
+ delay();
+ cp3 = code;
+ BRRI(Obeq, Ro2,Rzero, 0); // fp(Rfp) == 0
+ delay();
+
+ IRR(Olw, O(Frame,mr),Rfp, Ro3);
+ delay();
+ cp4 = code;
+ BRRI(Obeq, Ro3,Rzero, 0); // mr(Rfp) == 0
+ delay();
+
+ IRR(Olw, O(REG,M),Rreg, Ro2);
+ delay();
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ro2, Ro3);
+ delay();
+ IRR(Oaddui, -1,Ro3, Ro3);
+ cp5 = code;
+ BRRI(Obeq, Ro3,Rzero, 0); // --ref(arg) == 0
+ delay();
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ro2, Ro3);
+
+ IRR(Olw, O(Frame,mr),Rfp, Ro1);
+ delay();
+ IRR(Osw, O(REG,M),Rreg, Ro1);
+ IRR(Olw, O(Modlink,compiled),Ro1, Ro2); // check for uncompiled module
+ IRR(Olw, O(Modlink,MP),Ro1, Rmp);
+ cp6 = code;
+ BRRI(Obeq, Ro2,Rzero, 0);
+ IRR(Osw, O(REG,MP),Rreg, Rmp);
+
+ *cp4 |= (code - cp4) - 1;
+ JR(Ojalr, Rpic); // call destroy(t(fp))
+ delay();
+ IRR(Osw, O(REG,SP),Rreg, Rfp);
+ IRR(Olw, O(Frame,lr),Rfp, Ro1);
+ IRR(Olw, O(Frame,fp),Rfp, Rfp);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+ JR(Ojr, Ro1); // goto lr(Rfp)
+ delay();
+
+ *cp6 |= (code - cp6) - 1; // returning to uncompiled module
+ JR(Ojalr, Rpic); // call destroy(t(fp))
+ delay();
+ IRR(Osw, O(REG,SP),Rreg, Rfp);
+ IRR(Olw, O(Frame,lr),Rfp, Ro1);
+ IRR(Olw, O(Frame,fp),Rfp, Rfp);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,xpc),Rreg, Ro2);
+ JR(Ojr, Ro2); // return to uncompiled code
+ IRR(Osw, O(REG,PC),Rreg, Ro1);
+
+ *cp1 |= (code - cp1) - 1;
+ *cp2 |= (code - cp2) - 1;
+ *cp3 |= (code - cp3) - 1;
+ *cp5 |= (code - cp5) - 1;
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macindx(void)
+{
+
+ IRR(Olw, O(Array,t),Ro1, Ro2);
+ IRR(Olw, O(Array,data),Ro1, Ro1); // Ro1 = data
+ IRR(Olw, O(Type,size),Ro2, Ro2); // Ro2 = size
+ delay();
+
+ RRR(Omul, Ro3,Ro2,Rzero); // Ro2 = i*size
+ RRR(Omflo, Rzero,Rzero,Ro2);
+ JR(Ojr, Rlink);
+ RRR(Oaddu, Ro1,Ro2,Ro2); // Ro2 = i*size + data
+}
+
+static void
+maccase(void)
+{
+ ulong *cp1, *cp2, *cp3;
+
+/*
+ * Ro1 = value (input arg), t
+ * Ro2 = count, n
+ * Ro3 = table pointer (input arg)
+ * Ri = n/2, n2
+ * Rj = pivot element t+n/2*3, l
+ */
+
+ IRR(Olw, 0,Ro3, Ro2); // count
+ IRR(Oaddui, 0,Ro3, Rlink); // initial table pointer
+
+ cp1 = code; // loop:
+ BRI(Oblez,Ro2, 0); // n <= 0? goto out
+ SRR(Osra, 1, Ro2, Ri); // n2 = n>>1
+ SRR(Osll, 1, Ri, Rj);
+ RRR(Oaddu, Rj, Ri, Rj);
+ SRR(Osll, 2, Rj, Rj);
+ RRR(Oaddu, Ro3, Rj, Rj); // l = t + n2*3;
+ IRR(Olw, 4,Rj, Rpic);
+ delay();
+ RRR(Oslt, Rpic, Ro1, Rpic);
+ cp2 = code;
+ BRI(Obne, Rpic, 0); // v < l[1]? goto low
+ delay();
+
+ IRR(Olw, 8,Rj, Rpic);
+ delay();
+ RRR(Oslt, Rpic, Ro1, Rpic);
+ cp3 = code;
+ BRI(Obeq, Rpic, 0); // v >= l[2]? goto high
+ delay();
+
+ IRR(Olw, 12,Rj, Ro3); // found
+ delay();
+ JR(Ojr, Ro3);
+ delay();
+
+ *cp2 |= (code - cp2) - 1; // low:
+ BRRI(Obeq, Rzero,Rzero, (cp1-code)-1);
+ IRR(Oaddui, 0, Ri, Ro2); // n = n2
+
+ *cp3 |= (code - cp3) - 1; // high:
+ IRR(Oaddui, 12, Rj, Ro3); // t = l+3;
+ IRR(Oaddui, 1, Ri, Rpic);
+ BRRI(Obeq, Rzero,Rzero, (cp1-code)-1);
+ RRR(Osubu, Rpic, Ro2, Ro2); // n -= n2 + 1
+
+ *cp1 |= (code - cp1) - 1; // out:
+ IRR(Olw, 0,Rlink, Ro2); // initial n
+ delay();
+ SRR(Osll, 1, Ro2, Ro3);
+ RRR(Oaddu, Ro3, Ro2, Ro2);
+ SRR(Osll, 2, Ro2, Ro2);
+ RRR(Oaddu, Ro2, Rlink, Rlink);
+ IRR(Olw, 4,Rlink, Ro3); // (initital t)[n*3+1]
+ delay();
+ JR(Ojr, Ro3);
+ delay();
+}
+
+static void
+maclena(void)
+{
+ ulong *cp;
+
+ ldc((ulong)H, Ro1);
+ cp = code;
+ BRRI(Obeq, Ri,Ro1, 0);
+ delay();
+ IRR(Olw, O(Array,len),Ri, Ro1);
+ JR(Ojr, Rlink);
+ delay();
+ *cp |= (code - cp) - 1;
+ JR(Ojr, Rlink);
+ ldc(0, Ro1);
+}
+
+static void
+macmcal(void)
+{
+ ulong *cp1, *cp2;
+
+ IRR(Olw, O(Modlink,prog),Ri, Ro2);
+ IRR(Osw, O(Frame,lr),Ro1, Rlink); // f->lr = return
+ cp1 = code;
+ BRRI(Obne, Ro2, Rzero, 0); // CMPL ml->m->prog != 0
+ IRR(Oaddui, 0,Ro1, Rfp); // R.FP = f
+
+ IRR(Osw, O(REG,st),Rreg, Rlink);
+ ldc((ulong)rmcall, Rpic);
+ IRR(Osw, O(REG,FP),Rreg, Ro1);
+ IRR(Osw, O(REG,dt),Rreg, Rj);
+ JR(Ojalr, Rpic); // CALL rmcall
+ xchg();
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ JR(Ojr, Rlink);
+ delay();
+
+ *cp1 |= (code - cp1) - 1;
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+ IRR(Osw, O(REG,M),Rreg, Ri);
+ IRR(Oaddui, 1,Ro2, Ro2);
+ IRR(Olw, O(Modlink,MP),Ri, Rmp);
+ IRR(Olw, O(Modlink,compiled),Ri, Ro1);
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+ cp2 = code;
+ BRRI(Obeq, Ro1,Rzero, 0);
+ IRR(Osw, O(REG,MP),Rreg, Rmp);
+
+ JR(Ojr, Rj);
+ delay();
+
+ *cp2 |= (code - cp2) - 1;
+ IRR(Osw, O(REG,FP),Rreg, Rfp); // call to uncompiled code
+ IRR(Olw, O(REG,xpc),Rreg, Ro1);
+ JR(Ojr, Ro1);
+ IRR(Osw, O(REG,PC),Rreg, Rj);
+}
+
+static void
+macmfra(void)
+{
+ ldc((ulong)rmfram, Rpic);
+ IRR(Osw, O(REG,st),Rreg, Rlink);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+ IRR(Osw, O(REG,s),Rreg, Ri);
+ IRR(Osw, O(REG,d),Rreg, Rj);
+ JR(Ojalr, Rpic); // CALL rmfram
+ xchg();
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ JR(Ojr, Rlink);
+ delay();
+}
+
+static void
+macfram(void)
+{
+ ulong *cp;
+
+ /*
+ * Ri has t
+ */
+ IRR(Olw, O(Type,initialize),Ri, Rj);
+ IRR(Olw, O(Type,size),Ri, Ro3); // MOVL $t->size, Ro3
+ IRR(Olw, O(REG,SP),Rreg, Ro2); // MOVL R.SP, Ro2
+ IRR(Olw, O(REG,TS),Rreg, Ro1); // MOVL R.TS, Ro1
+ RRR(Oaddu,Ro3,Ro2, Ro2); // ADDL $t->size, Ro2
+ RRR(Osltu, Ro1,Ro2, Ro3); // CMP Ro1,Ro2,Ro3
+ cp = code;
+ BRI(Obne,Ro3,0); // BLT Ro3,**
+ delay();
+
+ IRR(Osw, O(REG,s),Rreg, Ri); // MOVL t, R.s
+ IRR(Osw, O(REG,st),Rreg, Rlink); // MOVL Rlink, R.st
+ ldc((ulong)extend, Rpic);
+ JR(Ojalr, Rpic); // CALL extend
+ IRR(Osw, O(REG,FP),Rreg, Rfp); // MOVL RFP, R.FP
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink); // reload registers
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ IRR(Olw, O(REG,s),Rreg, Ro1); // return arg
+ JR(Ojr, Rlink);
+ delay();
+
+ *cp |= (code - cp) - 1;
+ IRR(Olw, O(REG,SP),Rreg, Ro1);
+ IRR(Osw, O(REG,SP),Rreg, Ro2);
+ IRR(Osw, O(Frame,mr),Ro1, Rzero);
+ JR(Ojr, Rj); // return from tinit to main program
+ IRR(Osw, O(Frame,t),Ro1, Ri);
+}
+
+static void
+macmovm(void)
+{
+ ulong *cp1, *cp2;
+
+ /*
+ * from = Ro1
+ * to = Ro3
+ * count = Ro2
+ */
+
+ cp1 = code;
+ BRRI(Obeq, Ro2, Rzero, 0);
+ delay();
+
+ cp2 = code;
+ IRR(Olbu, 0,Ro1, Ri);
+ IRR(Oaddui, -1,Ro2, Ro2);
+ IRR(Osb, 0,Ro3, Ri);
+ IRR(Oaddui, 1,Ro1, Ro1);
+ BRRI(Obne, Ro2, Rzero, (cp2-code)-1);
+ IRR(Oaddui, 1,Ro3, Ro3);
+
+ *cp1 |= (code - cp1) - 1;
+ JR(Ojr, Rlink);
+ delay();
+}
+
+static void
+maccolr(void)
+{
+ ulong *cp;
+
+ IRR(Olw, 0,Ri, Ri);
+ IRR(Olw, O(Heap,color)-sizeof(Heap),Ro1, Ro3);
+
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ro1, Ro2);
+
+ cp = code;
+ BRRI(Obeq, Ri, Ro3, 0);
+ IRR(Oaddui, 1,Ro2, Ro2);
+
+ ldc(propagator, Ro3);
+ IRR(Osw, O(Heap,color)-sizeof(Heap),Ro1, Ro3);
+ ldc((ulong)&nprop, Ro3);
+ IRR(Osw, 0,Ro3, Ro1);
+
+ *cp |= (code - cp) - 1;
+ JR(Ojr, Rlink);
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ro1, Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ IRR(Osw, O(REG,dt),Rreg, Rlink);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ J(Ojal, base+macro[MacFRP]);
+ IRR(Olw, j,Rfp, Ri);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ IRR(Olw, O(REG,dt),Rreg, Rlink);
+ delay();
+ JR(Ojr, Rlink);
+ delay();
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ ldc((ulong)H, Ri);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ IRR(Osw, j,Ro1, Ri);
+ j += sizeof(WORD*);
+ }
+ }
+ JR(Ojr, Rlink);
+ xchg();
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096, 0);
+ if(tmp == nil)
+ return;
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 1)
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, tmp[512];
+
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ base = 0;
+
+ if(!comvec) {
+ i = 10; /* length of comvec */
+ code = malloc(i*sizeof(*code));
+ s = code;
+ preamble();
+ if(code >= (ulong*)(s + i))
+ urk("preamble");
+ comvec = (void*)s;
+ segflush(s, i*sizeof(*s));
+ if(cflag > 1) {
+ print("comvec\n");
+ while(s < code)
+ das(s++);
+ }/**/
+ }
+
+ mod = m;
+ n = 0;
+ regdelay = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ if(code >= &tmp[nelem(tmp)]) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("tmp ovflo");
+ }
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ code = tmp;
+ (*macinit[i].f)();
+ macro[macinit[i].o] = n;
+ n += code - tmp;
+ }
+
+ base = malloc((n+nlit)*sizeof(*base));
+ if(cflag > 1)
+ print("dis=%5d %5d mips=%5d asm=%.8p lit=%d: %s\n",
+ size, size*sizeof(Inst), n, base, nlit, m->name);
+
+ pass++;
+ code = base;
+ litpool = base+n;
+ n = 0;
+ nlit = 0;
+ regdelay = 0;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk(exCphase);
+ }
+ n += code - s;
+ if(cflag > 1) {
+ print("%3d %D\n", i, &m->prog[i]);
+ while(s < code)
+ das(s++);
+ }/**/
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ if(macro[macinit[i].o] != n) {
+ print("macinit %d\n", macinit[i].o);
+ urk(exCphase);
+ }
+ s = code;
+ (*macinit[i].f)();
+ n += code - s;
+ if(cflag > 1) {
+ print("macinit %d\n", macinit[i].o);
+ while(s < code)
+ das(s++);
+ }/**/
+ }
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(base+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(base+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(base+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+}
diff --git a/libinterp/comp-power.c b/libinterp/comp-power.c
new file mode 100644
index 00000000..25cc9f5b
--- /dev/null
+++ b/libinterp/comp-power.c
@@ -0,0 +1,2257 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+#define ROMABLE 0 /* costs something to zero patch vectors */
+#define RESCHED 1 /* check for interpreter reschedule */
+
+#define PATCH(ptr) *ptr |= ((ulong)code-(ulong)ptr) & 0xfffc
+
+#define T(r) *((void**)(R.r))
+
+#define XO(o,xo) (((o)<<26)|((xo)<<1))
+
+/* botch: ARRR, AIRR, LRRR, etc have dest first (will fix soon) */
+
+#define OPARRR(o,d,a,b) ((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define ARRR(o,d,a,b) gen((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define AIRR(o,d,a,v) gen((o)|((d)<<21)|((a)<<16)|((v)&0xFFFF))
+#define IRR(o,v,a,d) AIRR((o),(d),(a),(v))
+#define RRR(o,b,a,d) ARRR((o),(d),(a),(b))
+#define LRRR(o,a,s,b) ARRR((o),(s),(a),(b))
+#define LIRR(o,a,s,v) AIRR((o),(s),(a),(v))
+#define Bx(li,aa) gen((18<<26)|((li)&0x3FFFFFC)|((aa)<<1))
+#define RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+ (((mb)&31L)<<6)|(((me)&31L)<<1))
+#define MFSPR(s, d) gen(XO(31,339) | ((d)<<21) | ((s)<<11))
+#define MTSPR(s, d) gen(XO(31,467) | ((s)<<21) | ((d)<<11));
+
+#define SLWI(d,a,n) gen(slw((d),(a),(n),0))
+#define LRET() gen(Oblr)
+
+#define SETR0() if(macjit){ AIRR(Oaddi, Rzero, 0, 0); } /* set R0 to 0 */
+
+/* assumes H can be formed from signed halfword */
+#define CMPH(r) AIRR(Ocmpi, Rcrf0, (r), (ulong)H);
+#define NOTNIL(r) (CMPH((r)), CCALL(EQ, bounds))
+
+enum
+{
+ Rzero = 0, /* zero by design, not definition (P9/Inferno) */
+
+ Rsp = 1,
+ Rsb = 2,
+ Rarg = 3,
+
+ Ro1 = 8,
+ Ro2 = 9,
+ Ro3 = 10,
+ Ri = 11,
+ Rj = 12,
+
+ Rmp = 13,
+ Rfp = 14,
+ Rreg = 15,
+ Rta = 16, /* unused */
+ Rpic = 17, /* address for computed goto, for move to CTR or LR */
+
+ Rcon = 26, /* constant builder; temporary */
+ /* 27, 28, 29, 30 are potentially external registers (P9/Inferno) */
+ Rlink = 31, /* holds copies of LR; linker temp */
+
+ Rfret = 0,
+ Rf1 = 4,
+ Rf2 = 6,
+ Rfcvi = 27, /* floating conversion constant (P9/Inferno) */
+ Rfzero = 28, /* 0.0 (P9/Inferno) */
+ Rfhalf = 29, /* 0.5 (P9/Inferno) */
+
+ Rlr = 8<<5, /* SPR(LR) */
+ Rctr = 9<<5, /* SPR(CTR) */
+
+ Rcrf0 = 0, /* condition code field 0 */
+ Rcrf1 = 1<<2, /* condition code field 1 */
+
+ Rcrbrel = 31, /* condition code bit set to force relinquish */
+
+ Olwz = XO(32, 0),
+ Olwzu = XO(33, 0),
+ Olwzx = XO(31, 23),
+ Olbz = XO(34, 0),
+ Olbzu = XO(35, 0),
+ Olbzx = XO(31, 87),
+ Olfd = XO(50, 0),
+ Olhz = XO(40, 0),
+ Olhzx = XO(31, 279),
+ Ostw = XO(36, 0),
+ Ostwu = XO(37, 0),
+ Ostwx = XO(31, 151),
+ Ostb = XO(38, 0),
+ Ostbu = XO(39, 0),
+ Ostbx = XO(31, 215),
+ Osth = XO(44,0),
+ Osthx = XO(31, 407),
+ Ostfd = XO(54, 0),
+ Ostfdu = XO(55, 0),
+
+ Oaddc = XO(31,10),
+ Oadde = XO(31, 138),
+ Oaddi = XO(14, 0), /* simm */
+ Oaddic_ = XO(13, 0),
+ Oaddis = XO(15, 0),
+ Ocrxor = XO(19, 193),
+ Ofadd = XO(63, 21),
+ Ofcmpo = XO(63, 32),
+ Ofctiwz = XO(63, 15),
+ Ofsub = XO(63, 20),
+ Ofmr = XO(63, 72),
+ Ofmul = XO(63, 25),
+ Ofdiv = XO(63, 18),
+ Ofneg = XO(63, 40),
+ Oori = XO(24,0), /* uimm */
+ Ooris = XO(25,0), /* uimm */
+ Odivw = XO(31, 491),
+ Odivwu = XO(31, 459),
+ Omulhw = XO(31, 75),
+ Omulhwu = XO(31, 11),
+ Omulli = XO(7, 0),
+ Omullw = XO(31, 235),
+ Osubf = XO(31, 40),
+ Osubfc = XO(31,8),
+ Osubfe = XO(31,136),
+ Osubfic = XO(8, 0),
+ Oadd = XO(31, 266),
+ Oand = XO(31, 28),
+ Oneg = XO(31, 104),
+ Oor = XO(31, 444),
+ Oxor = XO(31, 316),
+
+ Ocmpi = XO(11, 0),
+ Ocmp = XO(31, 0),
+ Ocmpl = XO(31, 32),
+ Ocmpli = XO(10,0),
+
+ Orlwinm = XO(21, 0),
+ Oslw = XO(31, 24),
+ Osraw = XO(31,792),
+ Osrawi = XO(31,824),
+ Osrw = XO(31,536),
+
+ Cnone = OPARRR(0,20,0,0), /* unconditional */
+ Ceq = OPARRR(0,12,2,0),
+ Cle = OPARRR(0,4,1,0),
+ Clt = OPARRR(0,12,0,0),
+ Cdnz = OPARRR(0,16,0,0),
+ Cgt = OPARRR(0,12,1,0),
+ Cne = OPARRR(0,4,2,0),
+ Cge = OPARRR(0,4,0,0),
+ Cle1 = OPARRR(0,4,5,0), /* Cle on CR1 */
+ Crelq = OPARRR(0,12,Rcrbrel,0), /* relinquish */
+ Cnrelq = OPARRR(0,4,Rcrbrel,0), /* not relinquish */
+ Cpredict = OPARRR(0,1,0,0), /* reverse prediction */
+ Lk = 1,
+ Aa = 2,
+
+ Obeq = OPARRR(16<<26,12,2,0),
+ Obge = OPARRR(16<<26,4,0,0),
+ Obgt = OPARRR(16<<26,12,1,0),
+ Oble = OPARRR(16<<26,4,1,0),
+ Oblt = OPARRR(16<<26,12,0,0),
+ Obne = OPARRR(16<<26,4,2,0),
+
+ Ob = XO(18, 0),
+ Obc = XO(16, 0),
+ Obcctr = XO(19,528),
+ Obcctrl = Obcctr | Lk,
+ Obctr = Obcctr | Cnone,
+ Obctrl = Obctr | Lk,
+ Obclr = XO(19, 16),
+ Oblr = Obclr | Cnone,
+ Oblrl = Oblr | Lk,
+
+ Olea = 100, // pseudo op
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2), /* update R.PC */
+ TCHECK = (1<<3), /* check R.t for continue/ret */
+ NEWPC = (1<<4), /* goto R.PC */
+ DBRAN = (1<<5), /* dest is branch */
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR,
+ EQAND,
+
+ MacRET = 0,
+ MacFRP,
+ MacCASE,
+ MacFRAM,
+ MacCOLR,
+ MacMCAL,
+ MacMFRA,
+ MacCVTFW,
+ MacRELQ,
+ MacEND,
+ NMACRO
+};
+
+ void (*comvec)(void);
+ int macjit;
+extern long das(ulong*);
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static ulong* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+static void ldbigc(long, int);
+static void rdestroy(void);
+static void macret(void);
+static void macfrp(void);
+static void maccase(void);
+static void maccvtfw(void);
+static void macfram(void);
+static void maccolr(void);
+static void macend(void);
+static void macmcal(void);
+static void macmfra(void);
+static void macrelq(void);
+static void movmem(Inst*);
+
+struct
+{
+ int o;
+ void (*f)(void);
+} macinit[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacFRAM, macfram, /* frame instruction */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacCVTFW, maccvtfw,
+ MacRELQ, macrelq, /* reschedule */
+ MacEND, macend,
+ 0
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Frame *f;
+ Prog *p;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+void
+urk(char *s)
+{
+ print("compile failed: %s\n", s); // debugging
+ error(exCompile); // production
+}
+
+static void
+gen(ulong o)
+{
+ *code++ = o;
+}
+
+static void
+br(ulong op, ulong disp)
+{
+ *code++ = op | (disp & 0xfffc);
+}
+
+static void
+mfspr(int d, int s)
+{
+ MFSPR(s, d);
+}
+
+static void
+mtspr(int d, int s)
+{
+ MTSPR(s, d);
+}
+
+static ulong
+slw(int d, int s, int v, int rshift)
+{
+ int m0, m1;
+
+ if(v < 0 || v > 32)
+ urk("slw v");
+ if(v < 0)
+ v = 0;
+ else if(v > 32)
+ v = 32;
+ if(rshift) { /* shift right */
+ m0 = v;
+ m1 = 31;
+ v = 32-v;
+ } else {
+ m0 = 0;
+ m1 = 31-v;
+ }
+ return RLW(Orlwinm, d, s, v, m0, m1);
+}
+
+static void
+jr(int reg)
+{
+ mtspr(Rctr, reg); /* code would be faster if this were loaded well before branch */
+ gen(Obctr);
+}
+
+static void
+jrl(int reg)
+{
+ mtspr(Rctr, reg);
+ gen(Obctrl);
+}
+
+static void
+jrc(int op, int reg)
+{
+ mtspr(Rctr, reg);
+ gen(Obcctr | op);
+}
+
+static long
+brdisp(ulong *dest)
+{
+ ulong d, top;
+
+ d = (ulong)dest - (ulong)code;
+ if(!ROMABLE)
+ return d & 0x3fffffc;
+ top = d>>25;
+ if(top == 0 || top == 0x7F){
+ /* fits in 26-bit signed displacement */
+ return d & 0x3fffffc;
+ }
+ return -1;
+}
+
+static void
+jmp(ulong *dest)
+{
+ long d;
+
+ if((d = brdisp(dest)) < 0){
+ ldbigc((ulong)dest, Rpic); /* Rpic & Rctr must be free */
+ jr(Rpic);
+ } else
+ gen(Ob | d);
+}
+
+static void
+jmpl(ulong *dest)
+{
+ long d;
+
+ if((d = brdisp(dest)) < 0){
+ ldbigc((ulong)dest, Rpic); /* Rpic must be free */
+ jrl(Rpic);
+ } else
+ gen(Ob | d | Lk);
+}
+
+static void
+jmpc(int op, ulong *dest)
+{
+ ldbigc((ulong)dest, Rpic);
+ jrc(op, Rpic);
+}
+
+static int
+bigc(long c)
+{
+ if(c >= -0x8000 && c <= 0x7FFF)
+ return 0;
+ return 1;
+}
+
+static void
+ldbigc(long c, int reg)
+{
+ AIRR(Oaddis, reg,Rzero,c>>16);
+ LIRR(Oori, reg,reg,c);
+}
+
+static void
+ldc(long c, int reg)
+{
+ if(!bigc(c))
+ AIRR(Oaddi, reg, Rzero, c);
+ else if((ulong)c <= 0xFFFF)
+ LIRR(Oori, reg, Rzero, c);
+ else if((c&0xFFFF) == 0)
+ LIRR(Ooris, reg, Rzero, c>>16);
+ else {
+ AIRR(Oaddis, reg,Rzero,c>>16);
+ LIRR(Oori, reg,reg,c);
+ }
+}
+
+static void
+mem(int inst, long disp, int rm, int r)
+{
+ if(bigc(disp)) {
+ ldc(disp, Rcon);
+ switch(inst){
+ default: urk("mem op"); break;
+ case Olea: inst = Oadd; break;
+ case Olwz: inst = Olwzx; break;
+ case Olbz: inst = Olbzx; break;
+ case Olhz: inst = Olhzx; break;
+ case Ostw: inst = Ostwx; break;
+ case Ostb: inst = Ostbx; break;
+ case Osth: inst = Osthx; break;
+ }
+ ARRR(inst, r, Rcon, rm);
+ } else {
+ if(inst == Olea)
+ inst = Oaddi;
+ AIRR(inst, r, rm,disp);
+ }
+}
+
+static void
+opx(int mode, Adr *a, int op, int reg)
+{
+ ulong c;
+ int r, rx, lea;
+
+ lea = 0;
+ if(op == Olea){
+ lea = 1;
+ op = Oaddi;
+ }
+ switch(mode) {
+ case AFP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 1");
+ AIRR(op, reg, Rfp,c);
+ break;
+ case AMP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 2");
+ AIRR(op, reg, Rmp,c);
+ break;
+ case AIMM:
+ if(lea) {
+ if(a->imm != 0) {
+ ldc(a->imm, reg);
+ AIRR(Ostw, reg, Rreg,O(REG,st));
+ } else
+ AIRR(Ostw, Rzero, Rreg,O(REG,st));
+ AIRR(Oaddi, reg, Rreg,O(REG,st));
+ } else
+ ldc(a->imm, reg);
+ return;
+ case AIND|AFP:
+ r = Rfp;
+ goto offset;
+ case AIND|AMP:
+ r = Rmp;
+ offset:
+ c = a->i.s;
+ rx = Ri;
+ if(lea || op == Olwz)
+ rx = reg;
+ AIRR(Olwz, rx, r,a->i.f);
+ if(!lea || c != 0)
+ AIRR(op, reg, rx,c);
+ break;
+ }
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+ opx(USRC(i->add), &i->s, op, reg);
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+ opx(UDST(i->add), &i->d, op, reg);
+}
+
+static void
+op2(Inst *i, int op, int reg)
+{
+ int lea;
+
+ lea = 0;
+ if(op == Olea){
+ op = Oaddi;
+ lea = 1;
+ }
+ switch(i->add & ARM) {
+ case AXNON:
+ if(lea)
+ op = Olea;
+ opwst(i, op, reg);
+ return;
+ case AXIMM:
+ if(lea)
+ urk("op2/lea");
+ ldc((short)i->reg, reg);
+ return;
+ case AXINF:
+ IRR(op, i->reg,Rfp, reg);
+ break;
+ case AXINM:
+ IRR(op, i->reg,Rmp, reg);
+ break;
+ }
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+ int o1, o2;
+
+ o1 = Olwz;
+ if(b1flag)
+ o1 = Olbz;
+ o2 = Olwz;
+ if(b2flag)
+ o2 = Olbz;
+ if((i->add & ARM) == AXIMM) {
+ opwld(i, o1, Ro1);
+ op2(i, o2, Ro2);
+ } else {
+ op2(i, o2, Ro2);
+ opwld(i, o1, Ro1);
+ }
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+ opwld(i, o1, Ro1);
+ opwst(i, o2, Ro1);
+}
+
+static ulong
+branch(Inst *i)
+{
+ ulong rel;
+
+ if(base == 0)
+ return 0;
+ rel = (ulong)(base+patch[i->d.ins - mod->prog]);
+ rel -= (ulong)code;
+ if(rel & 3 || (long)rel <= -(1<<16) || (long)rel >= 1<<16)
+ urk("branch off");
+ return rel & 0xfffc;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ ulong *cp;
+
+ if(i != nil && i->d.ins != nil && i->d.ins > i)
+ return; /* only backwards jumps can loop: needn't check forward ones */
+ cp = code;
+ gen(Obc | Cnrelq | Cpredict);
+ jmpl(base+macro[MacRELQ]);
+ PATCH(cp);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ ldbigc((ulong)litpool, Ro1);
+ IRR(Ostw, roff, Rreg, Ro1);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+bounds(void)
+{
+ /* mem(Ostw, O(REG,FP), Rreg, Rfp); */
+ error(exBounds);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, Ro1);
+ mem(Ostw, O(REG, s), Rreg, Ro1);
+ }
+ }
+ if(m & DSTOP) {
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, O(REG,d),Rreg, Ro3);
+ }
+ if(m & WRTPC) {
+ pc = patch[i-mod->prog+1];
+ ldbigc((ulong)(base+pc), Ro1);
+ IRR(Ostw, O(REG,PC),Rreg, Ro1);
+ }
+ if(m & DBRAN) {
+ pc = patch[i->d.ins-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ IRR(Olwz, O(REG,d),Rreg, Ro2);
+ IRR(Ostw, O(REG,m),Rreg, Ro2);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG,m));
+ break;
+ case AXINF:
+ mem(Olea, i->reg, Rfp, Ro2);
+ mem(Ostw, O(REG, m), Rreg, Ro2);
+ break;
+ case AXINM:
+ mem(Olea, i->reg, Rmp, Ro2);
+ mem(Ostw, O(REG, m), Rreg, Ro2);
+ break;
+ }
+ IRR(Ostw, O(REG,FP),Rreg, Rfp);
+
+ jmpl((ulong*)fn);
+
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ if(m & TCHECK) {
+ IRR(Olwz, O(REG,t),Rreg, Ro1);
+ IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+ IRR(Ocmpi, 0, Ro1, Rcrf0);
+ mtspr(Rctr, Ro2);
+ gen(Obcctr | Cne);
+ }
+ IRR(Olwz, O(REG,FP),Rreg, Rfp);
+ IRR(Olwz, O(REG,MP),Rreg, Rmp);
+
+ if(m & NEWPC) {
+ IRR(Olwz, O(REG,PC),Rreg, Ro1);
+ jr(Ro1);
+ }
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ opwld(i, Olwz, Ro2);
+ opwst(i, Olea, Ro3);
+ SLWI(Ro2, Ro2, 2);
+ ARRR(Olwzx, Ro1, Ro3,Ro2);
+ jr(Ro1);
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)(base + patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Olwz, Ro1); // v
+ opwst(i, Olea, Ro3); // table
+ jmp(base+macro[MacCASE]);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)(base + patch[t[2]]);
+ t += 3;
+ }
+ t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ ulong *cp1, *cp2;
+
+ opwld(i, Olwz, Ri); // must use Ri for MacFRAM
+ CMPH(Ri);
+ cp1 = code;
+ br(Obeq, 0);
+
+ if((i->add&ARM) == AXIMM) {
+ mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), Ri, Ri);
+ } else {
+ op2(i, Olwz, Ro2);
+ SLWI(Ro2, Ro2, 3); // assumes sizeof(Modl) == 8
+ ARRR(Oadd, Ri, Ro2, Ro2);
+ mem(Olwz, OA(Modlink, links)+O(Modl, frame), Ri, Ri);
+ }
+
+ AIRR(Olwz, Ro2, Ri,O(Type,initialize));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp2 = code;
+ br(Obne, 0);
+
+ opwst(i, Olea, Rj);
+
+ PATCH(cp1);
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Rpic);
+ mtspr(Rlr, Rpic);
+ jmp(base+macro[MacMFRA]);
+
+ PATCH(cp2);
+ jmpl(base+macro[MacFRAM]);
+ opwst(i, Ostw, Ro1);
+}
+
+static void
+commcall(Inst *i)
+{
+ opwld(i, Olwz, Ro1); // f in Ro1
+ AIRR(Olwz, Ro3, Rreg,O(REG,M));
+ AIRR(Ostw, Rfp, Ro1,O(Frame,fp)); // f->fp = R.FP
+ AIRR(Ostw, Ro3, Ro1,O(Frame,mr)); // f->mr = R.M
+ opwst(i, Olwz, Ri);
+ if((i->add&ARM) == AXIMM) {
+ mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), Ri, Rj); // ml->entry in Rj
+ } else {
+ op2(i, Olwz, Rj);
+ SLWI(Rj, Rj, 3); // assumes sizeof(Modl) == 8
+ ARRR(Oadd, Ri, Rj, Rj);
+ mem(Olwz, OA(Modlink, links)+O(Modl, u.pc), Rj, Rj);
+ }
+ jmpl(base+macro[MacMCAL]);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Obge:
+ return Oble;
+ case Oble:
+ return Obge;
+ case Obgt:
+ return Oblt;
+ case Oblt:
+ return Obgt;
+ }
+ return b;
+}
+
+static void
+cbra(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM) && !bigc(i->s.imm)) {
+ op2(i, Olwz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm);
+ op = swapbraop(op);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Olwz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->reg);
+ } else {
+ op12(i, 0, 0);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ }
+ br(op, branch(i));
+}
+
+static void
+cbrab(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ op2(i, Olbz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm&0xFF);
+ op = swapbraop(op);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Olbz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->reg&0xFF); // mask i->reg?
+ } else {
+ op12(i, 1, 1);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ }
+ br(op, branch(i));
+}
+
+static void
+cbraf(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olfd, Rf1);
+ op2(i, Olfd, Rf2);
+ ARRR(Ofcmpo, Rcrf0, Rf1, Rf2);
+ br(op, branch(i));
+}
+
+static void
+cbral(Inst *i, int cms, int cls, int mode)
+{
+ ulong *cp;
+
+ if(RESCHED)
+ schedcheck(i);
+ cp = nil;
+ opwld(i, Olea, Ri);
+ op2(i, Olea, Rj);
+ IRR(Olwz, 0,Ri, Ro1);
+ IRR(Olwz, 0,Rj, Ro2);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ switch(mode) {
+ case ANDAND:
+ cp = code;
+ br(cms, 0);
+ break;
+ case OROR:
+ br(cms, branch(i));
+ break;
+ case EQAND:
+ br(cms, branch(i));
+ cp = code;
+ br(Obne, 0);
+ break;
+ }
+ IRR(Olwz, 4,Ri, Ro1);
+ IRR(Olwz, 4,Rj, Ro2);
+ ARRR(Ocmpl, Rcrf0, Ro1, Ro2);
+ br(cls, branch(i));
+ if(cp)
+ PATCH(cp);
+}
+
+static void
+shrl(Inst *i)
+{
+// int c;
+
+// if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+// }
+/*
+ c = i->s.imm;
+ op2(i, Olea, Ro3);
+ IRR(Olwz, 0,Ro3, Ro1);
+ if(c >= 32) {
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ SRR(Osra, 31, Ro1, Ro2);
+ IRR(Ostw, 0,Ro3, Ro2);
+ if(c >= 64) {
+ IRR(Ostw, 4,Ro3, Ro2);
+ return;
+ }
+ if(c > 32)
+ SRR(Osra, c-32, Ro1, Ro1);
+ IRR(Ostw, 4,Ro3, Ro1);
+ return;
+ }
+ IRR(Olwz, 4,Ro3, Ro2);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ if(c != 0) {
+ SRR(Osll, 32-c, Ro1, Ri);
+ SRR(Osra, c, Ro1, Ro1);
+ SRR(Osrl, c, Ro2, Ro2);
+ RRR(Oor, Ri, Ro2, Ro2);
+ }
+ IRR(Ostw, 4,Ro3, Ro2);
+ IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+shll(Inst *i)
+{
+// int c;
+
+// if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+// }
+/*
+ c = i->s.imm;
+ if(c >= 64) {
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 0,Ro3, Rzero);
+ IRR(Ostw, 4,Ro3, Rzero);
+ return;
+ }
+ op2(i, Olea, Ro3);
+ if(c >= 32) {
+ IRR(Olwz, 4,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 4,Ro3, Rzero);
+ if(c > 32)
+ SRR(Osll, c-32, Ro1, Ro1);
+ IRR(Ostw, 0,Ro3, Ro1);
+ return;
+ }
+ IRR(Olwz, 4,Ro3, Ro2);
+ IRR(Olwz, 0,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ if(c != 0) {
+ SRR(Osrl, 32-c, Ro2, Ri);
+ SRR(Osll, c, Ro2, Ro2);
+ SRR(Osll, c, Ro1, Ro1);
+ RRR(Oor, Ri, Ro1, Ro1);
+ }
+ IRR(Ostw, 4,Ro3, Ro2);
+ IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int o, q, b;
+ ulong *cp, *cp1;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTCL:
+ case ICVTLC:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTFL:
+ case ICVTLF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTWB:
+ op13(i, Olwz, Ostb);
+ break;
+ case ICVTBW:
+ op13(i, Olbz, Ostw);
+ break;
+ case IMOVB:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ opwst(i, Ostb, Rzero);
+ break;
+ }
+ op13(i, Olbz, Ostb);
+ break;
+ case IMOVW:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ opwst(i, Ostw, Rzero);
+ break;
+ }
+ op13(i, Olwz, Ostw);
+ break;
+ case ICVTLW:
+ opwld(i, Olea, Ro1);
+ AIRR(Olwz, Ro2, Ro1,4);
+ opwst(i, Ostw, Ro2);
+ break;
+ case ICVTWL:
+ opwld(i, Olwz, Ro1);
+ opwst(i, Olea, Ro2);
+ LRRR(Osrawi, Ro3, Ro1, 31);
+ AIRR(Ostw, Ro1, Ro2,4);
+ AIRR(Ostw, Ro3, Ro2,0);
+ break;
+ case IHEADM:
+ opwld(i, Olwz, Ro1);
+ AIRR(Oaddi, Ro1, Ro1,OA(List,data));
+ movmem(i);
+ break;
+ case IMOVM:
+ opwld(i, Olea, Ro1);
+ movmem(i);
+ break;
+ case IRET:
+ jmp(base+macro[MacRET]);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ ldc((ulong)mod->type[i->s.imm], Ri);
+ jmpl(base+macro[MacFRAM]);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILEA:
+ op13(i, Olea, Ostw);
+ break;
+ case IHEADW:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,OA(List,data));
+ opwst(i, Ostw, Ro1);
+ break;
+ case IHEADF:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olfd, Rf1, Ro1,OA(List,data));
+ opwst(i, Ostfd, Rf1);
+ break;
+ case IHEADB:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olbz, Ro1, Ro1,OA(List,data));
+ opwst(i, Ostb, Ro1);
+ break;
+ case ITAIL:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,O(List,tail));
+ goto movp;
+ case IMOVP:
+ opwld(i, Olwz, Ro1);
+ goto movp;
+ case IHEADP:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,OA(List,data));
+ movp:
+ CMPH(Ro1);
+ cp = code;
+ br(Obeq, 0);
+ jmpl(base+macro[MacCOLR]);
+ PATCH(cp);
+ opwst(i, Olea, Ro3);
+ AIRR(Olwz, Ri, Ro3,0);
+ AIRR(Ostw, Ro1, Ro3,0);
+ jmpl(base+macro[MacFRP]);
+ break;
+ case ILENA:
+ opwld(i, Olwz, Ri);
+ ldc(0, Ro1);
+ CMPH(Ri);
+ cp = code;
+ br(Obeq, 0);
+ AIRR(Olwz, Ro1, Ri,O(Array,len));
+ PATCH(cp);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILENC:
+ opwld(i, Olwz, Ri);
+ ldc(0, Ro1);
+ CMPH(Ri);
+ cp = code;
+ br(Obeq, 0);
+ AIRR(Olwz, Ro1, Ri,O(String,len));
+ AIRR(Ocmpi, Rcrf0, Ro1, 0);
+ br(Obge, 2*4); // BGE 2(PC); skip
+ ARRR(Oneg, Ro1, Ro1, 0);
+ PATCH(cp);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILENL:
+ opwld(i, Olwz, Ro1);
+ ldc(0, Ro3);
+ CMPH(Ro1);
+ cp = code;
+ br(Obeq, 0);
+
+ cp1 = code;
+ AIRR(Olwz, Ro1, Ro1,O(List,tail));
+ AIRR(Oaddi, Ro3, Ro3, 1);
+ CMPH(Ro1);
+ br(Obne, ((ulong)cp1-(ulong)code));
+
+ PATCH(cp);
+ opwst(i, Ostw, Ro3);
+ break;
+ case IMOVL:
+ opwld(i, Olea, Ro1);
+ AIRR(Olwz, Ro2, Ro1,0);
+ AIRR(Olwz, Ro3, Ro1,4);
+ opwst(i, Olea, Ro1);
+ AIRR(Ostw, Ro2, Ro1,0);
+ AIRR(Ostw, Ro3, Ro1,4);
+ break;
+ case IMOVF:
+ opwld(i, Olfd, Rf1);
+ opwst(i, Ostfd, Rf1);
+ break;
+ case ICVTFW:
+ if(!macjit){
+ opwld(i, Olfd, Rf1);
+ jmpl(base+macro[MacCVTFW]);
+ opwst(i, Ostw, Ro1);
+ break;
+ }
+ case ICVTWF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEGF:
+ opwld(i, Olfd, Rf1);
+ ARRR(Ofneg, Rf2, 0, Rf1);
+ opwst(i, Ostfd, Rf2);
+ break;
+ case IXORL:
+ case IORL:
+ case IANDL:
+ case IADDL:
+ case ISUBL:
+ opwld(i, Olea, Ro1);
+ op2(i, Olea, Ro3);
+
+ AIRR(Olwz, Rj, Ro1,4); /* ls */
+ AIRR(Olwz, Ro2, Ro3,4);
+ AIRR(Olwz, Ri, Ro1,0); /* ms */
+ AIRR(Olwz, Ro1, Ro3,0);
+
+ switch(i->op) {
+ case IXORL:
+ o = Oxor;
+ goto l1;
+ case IORL:
+ o = Oor;
+ goto l1;
+ case IANDL:
+ o = Oand;
+ l1:
+ LRRR(o, Ro1, Ri, Ro1);
+ LRRR(o, Ro2, Rj, Ro2);
+ break;
+ case IADDL:
+ RRR(Oaddc, Rj,Ro2, Ro2);
+ RRR(Oadde, Ri,Ro1, Ro1);
+ break;
+ case ISUBL:
+ RRR(Osubfc, Ro2,Rj, Ro2);
+ RRR(Osubfe, Ro1,Ri, Ro1);
+ break;
+ }
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 0,Ro3, Ro1);
+ IRR(Ostw, 4,Ro3, Ro2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IADDF: o = Ofadd; goto f1;
+ case ISUBF: o = Ofsub; goto f1;
+ case IMULF: o = Ofmul; goto f1;
+ case IDIVF: o = Ofdiv; goto f1;
+ f1:
+ opwld(i, Olfd, Rf1);
+ op2(i, Olfd, Rf2);
+ if(o == Ofmul)
+ gen(o | (Rf2<<21) | (Rf2<<16) | (Rf1<<6)); /* odd one out: op D,A,-,C */
+ else
+ ARRR(o, Rf2, Rf2, Rf1);
+ opwst(i, Ostfd, Rf2);
+ break;
+
+ case IBEQF:
+ cbraf(i, Obeq);
+ break;
+ case IBGEF:
+ cbraf(i, Obge);
+ case IBGTF:
+ cbraf(i, Obgt);
+ break;
+ case IBLEF:
+ cbraf(i, Oble);
+ break;
+ case IBLTF:
+ cbraf(i, Oblt);
+ break;
+ case IBNEF:
+ cbraf(i, Obne);
+ break;
+
+ case IBLTB:
+ cbrab(i, Oblt);
+ break;
+ case IBLEB:
+ cbrab(i, Oble);
+ break;
+ case IBGTB:
+ cbrab(i, Obgt);
+ break;
+ case IBGEB:
+ cbrab(i, Obge);
+ break;
+ case IBEQB:
+ cbrab(i, Obeq);
+ break;
+ case IBNEB:
+ cbrab(i, Obne);
+ break;
+
+ case IBLTW:
+ cbra(i, Oblt);
+ break;
+ case IBLEW:
+ cbra(i, Oble);
+ break;
+ case IBGTW:
+ cbra(i, Obgt);
+ break;
+ case IBGEW:
+ cbra(i, Obge);
+ break;
+ case IBEQW:
+ cbra(i, Obeq);
+ break;
+ case IBNEW:
+ cbra(i, Obne);
+ break;
+
+ case IBEQL:
+ cbral(i, Obne, Obeq, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, Obne, OROR);
+ break;
+ case IBLTL:
+ cbral(i, Oblt, Oblt, EQAND);
+ break;
+ case IBLEL:
+ cbral(i, Oblt, Oble, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Obgt, Obgt, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Obgt, Obge, EQAND);
+ break;
+
+ case ISUBB:
+ case IADDB:
+ case IANDB:
+ case IORB:
+ case IXORB:
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ b = 1;
+ op12(i, b, b);
+ goto s2;
+ case ISHLB:
+ case ISHRB:
+ b = 1;
+ op12(i, 0, b);
+ goto s2;
+ case ISUBW:
+ case IADDW:
+ case IANDW:
+ case IORW:
+ case IXORW:
+ case ISHLW:
+ case ISHRW:
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ b = 0;
+ op12(i, b, b);
+ s2:
+ q = 0;
+ switch(i->op) {
+ case ISUBB:
+ case ISUBW: o = Osubf; q = Osubfic;
+ // TO DO: if immediate operand, should use opcode q
+ USED(q);
+ ARRR(o, Ro3, Ro1, Ro2);
+ break;
+ case IADDB:
+ case IADDW: o = Oadd; q = Oaddi; goto c1;
+ case IMULB:
+ case IMULW: o = Omullw; q = Omulli; goto c1;
+ case IDIVB:
+ case IDIVW: o = Odivw; goto c1;
+ c1:
+ // TO DO: if immediate operand, should use opcode q
+ USED(q);
+ ARRR(o, Ro3, Ro2, Ro1);
+ break;
+ case IANDB:
+ case IANDW: o = Oand; goto c2;
+ case IORB:
+ case IORW: o = Oor; goto c2;
+ case IXORB:
+ case IXORW: o = Oxor; goto c2;
+ case ISHLB:
+ case ISHLW: o = Oslw; goto c2;
+ case ISHRB:
+ case ISHRW: o = Osraw; goto c2;
+ c2:
+ LRRR(o, Ro3,Ro2,Ro1);
+ break;
+ case IMODB:
+ case IMODW:
+ ARRR(Odivw, Ro3, Ro2, Ro1);
+ ARRR(Omullw, Ro3, Ro3, Ro1);
+ ARRR(Osubf, Ro3, Ro3, Ro2);
+ break;
+ }
+ opwst(i, b? Ostb: Ostw, Ro3);
+ break;
+ case ICALL:
+ opwld(i, Olwz, Ro1); /* f = T(s) */
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2); /* R.pc */
+ AIRR(Ostw, Rfp, Ro1,O(Frame,fp)); /* f->fp = R.fp */
+ AIRR(Ostw, Ro2, Ro1,O(Frame,lr)); /* f->lr = R.pc */
+ AIRR(Oaddi, Rfp, Ro1, 0); /* R.fp = (uchar*)f */
+ jmp(base+patch[i->d.ins - mod->prog]);
+ break;
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ jmp(base+patch[i->d.ins - mod->prog]);
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IINDC:
+ opwld(i, Olwz, Ro1); // Ro1 = string
+ if((i->add&ARM) != AXIMM)
+ op2(i, Olwz, Ro2); // Ro2 = i
+ AIRR(Olwz, Ri, Ro1,O(String,len)); // len<0 => index Runes, otherwise bytes
+ AIRR(Oaddi, Ro1, Ro1,O(String,data));
+ AIRR(Ocmpi, Rcrf0, Ri, 0);
+ if(bflag){
+ br(Obge, 2*4);
+ ARRR(Oneg, Ri, Ri, 0);
+ if((i->add&ARM) != AXIMM)
+ ARRR(Ocmpl, Rcrf1, Ri, Ro2); /* CMPU len, i */
+ else
+ AIRR(Ocmpli, Rcrf1, Ri, i->reg); /* CMPU len, i */
+ jmpc(Cle1, (ulong*)bounds);
+ }
+ cp = code;
+ br(Obge, 0);
+ if((i->add&ARM) != AXIMM){
+ SLWI(Ro2, Ro2, 1);
+ ARRR(Olhzx, Ro3, Ro1, Ro2);
+ } else
+ mem(Olhz, (short)i->reg<<1, Ro1, Ro3);
+ gen(Ob | (2*4)); // skip
+ PATCH(cp);
+ if((i->add&ARM) != AXIMM)
+ ARRR(Olbzx, Ro3, Ro1, Ro2);
+ else
+ AIRR(Olbz, Ro3, Ro1,i->reg);
+ opwst(i, Ostw, Ro3);
+ break;
+ case IINDX:
+ case IINDB:
+ case IINDF:
+ case IINDW:
+ case IINDL:
+ opwld(i, Olwz, Ro1); /* Ro1 = a */
+ opwst(i, Olwz, Ro3); /* Ro3 = i */
+ if(bflag){
+ AIRR(Olwz, Ro2, Ro1, O(Array, len)); /* Ro2 = a->len */
+ ARRR(Ocmpl, Rcrf0, Ro3, Ro2); /* CMPU i, len */
+ jmpc(Cge, (ulong*)bounds);
+ }
+ // TO DO: check a != H
+ AIRR(Olwz, Ro2, Ro1,O(Array,data)); /* Ro2 = a->data */
+ switch(i->op) {
+ case IINDX:
+ AIRR(Olwz, Ri, Ro1,O(Array,t)); // Ri = a->t
+ AIRR(Olwz, Ro1, Ri,O(Type,size)); // Ro1 = a->t->size
+ ARRR(Omullw, Ro3, Ro3, Ro1); // Ro3 = i*size
+ break;
+ case IINDL:
+ case IINDF:
+ SLWI(Ro3, Ro3, 3); /* Ro3 = i*8 */
+ break;
+ case IINDW:
+ SLWI(Ro3, Ro3, 2); /* Ro3 = i*4 */
+ break;
+ case IINDB:
+ /* no further work */
+ break;
+ }
+ ARRR(Oadd, Ro2, Ro2, Ro3); /* Ro2 = i*size + data */
+ op2(i, Ostw, Ro2);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+enum {
+ PREFLEN = 20, /* max instruction words in comvec */
+};
+
+static void
+preamble(void)
+{
+ ulong *s;
+
+ if(comvec != nil)
+ return;
+ s = code = malloc(PREFLEN*sizeof(*code));
+ if(s == nil)
+ error(exNomem);
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,xpc));
+ AIRR(Olwz, Ri, Rreg,O(REG,PC));
+ mtspr(Rctr, Ri);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Obctr);
+ if(code >= (ulong*)(s + PREFLEN))
+ urk("preamble");
+ comvec = (void*)s;
+ segflush(s, PREFLEN*sizeof(*s));
+ if(cflag > 3) {
+ print("comvec\n");
+ while(s < code)
+ s += das(s);
+ }
+}
+
+static void
+macfrp(void)
+{
+ CMPH(Ri);
+ gen(Obclr | Ceq); // arg == $H? => return
+
+ AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Oaddic_, Rj, Ro2, -1); // ref(arg)-- and test
+ AIRR(Ostw, Rj, Ri,O(Heap,ref)-sizeof(Heap));
+ gen(Obclr | Cne); // ref(arg) nonzero? => return
+
+ AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap)); // restore ref count of 1 for destroy
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+ AIRR(Ostw, Ri, Rreg,O(REG,s));
+
+ jmpl((ulong*)rdestroy); // CALL destroy
+
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ LRET();
+}
+
+static void
+macret(void)
+{
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+ Inst i;
+
+ AIRR(Olwz, Ro1, Rfp,O(Frame,t));
+ AIRR(Ocmpi, Rcrf0, Ro1, 0);
+ cp1 = code;
+ br(Obeq, 0); // t(Rfp) == 0
+
+ AIRR(Olwz, Rpic, Ro1,O(Type,destroy));
+ AIRR(Ocmpi, Rcrf0, Rpic, 0);
+ cp2 = code;
+ br(Obeq, 0); // destroy(t(fp)) == 0
+
+ AIRR(Olwz, Ro2, Rfp,O(Frame,fp));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp3 = code;
+ br(Obeq, 0); // fp(Rfp) == 0
+
+ AIRR(Olwz, Ro3, Rfp,O(Frame,mr));
+ AIRR(Ocmpi, Rcrf0, Ro3, 0);
+ cp4 = code;
+ br(Obeq, 0); // mr(Rfp) == 0
+
+ AIRR(Olwz, Ro2, Rreg,O(REG,M));
+ AIRR(Olwz, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+ AIRR(Oaddic_, Ro3, Ro3, -1); // --ref(arg), set cc
+ cp5 = code;
+ br(Obeq, 0); // --ref(arg) == 0?
+ AIRR(Ostw, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+
+ AIRR(Olwz, Ro1, Rfp,O(Frame,mr));
+ AIRR(Ostw, Ro1, Rreg,O(REG,M));
+ AIRR(Olwz, Rmp, Ro1,O(Modlink,MP));
+ AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro3, Ro1,O(Modlink,compiled)); // R.M->compiled?
+ AIRR(Ocmpi, Rcrf0, Ro3, 0);
+ linterp = code;
+ br(Obeq, 0);
+
+ PATCH(cp4);
+ jrl(Rpic); // call destroy(t(fp))
+ AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+ AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+ AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ jr(Ro1); // goto lr(Rfp)
+
+ PATCH(linterp);
+ jrl(Rpic); // call destroy(t(fp))
+ AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+ AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+ AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+ AIRR(Ostw, Ro1, Rreg,O(REG,PC)); // R.PC = fp->lr
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+ mtspr(Rlr, Rpic);
+ gen(Oblr); // return to xec uncompiled code
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccase(void)
+{
+ ulong *cp1, *cp2, *cp3, *loop;
+
+/*
+ * Ro1 = value (input arg), t
+ * Ro2 = count, n
+ * Ro3 = table pointer (input arg)
+ * Ri = n/2, n2
+ * Rj = pivot element t+n/2*3, l
+ */
+
+ IRR(Olwz, 0,Ro3, Ro2); // count
+ IRR(Oaddi, 0,Ro3, Rlink); // initial table pointer
+
+ loop = code; // loop:
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp1 = code;
+ br(Oble, 0); // n <= 0? goto out
+ LRRR(Osrawi, Ri, Ro2, 1); // n2 = n>>1
+ SLWI(Rj, Ri, 1);
+ ARRR(Oadd, Rj, Rj, Ri);
+ SLWI(Rj, Rj, 2);
+ ARRR(Oadd, Rj, Rj, Ro3); // l = t + n2*3;
+ AIRR(Olwz, Rpic, Rj,4);
+ ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+ cp2 = code;
+ br(Oblt, 0); // v < l[1]? goto low
+
+ IRR(Olwz, 8,Rj, Rpic);
+ ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+ cp3 = code;
+ br(Obge, 0); // v >= l[2]? goto high
+
+ IRR(Olwz, 12,Rj, Ro3); // found
+ jr(Ro3);
+
+ PATCH(cp2); // low:
+ IRR(Oaddi, 0, Ri, Ro2); // n = n2
+ jmp(loop);
+
+ PATCH(cp3); // high:
+ IRR(Oaddi, 12, Rj, Ro3); // t = l+3;
+ IRR(Oaddi, 1, Ri, Rpic);
+ RRR(Osubf, Ro2, Rpic, Ro2); // n -= n2 + 1
+ jmp(loop);
+
+ PATCH(cp1); // out:
+ IRR(Olwz, 0,Rlink, Ro2); // initial n
+ SLWI(Ro3, Ro2, 1);
+ RRR(Oadd, Ro3, Ro2, Ro2);
+ SLWI(Ro2, Ro2, 2);
+ RRR(Oadd, Ro2, Rlink, Rlink);
+ IRR(Olwz, 4,Rlink, Ro3); // (initial t)[n*3+1]
+ jr(Ro3);
+}
+
+static void
+macmcal(void)
+{
+ ulong *cp;
+
+ AIRR(Olwz, Ro2, Ri,O(Modlink,prog));
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Ro1,O(Frame,lr)); // f->lr = return
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ AIRR(Oaddi, Rfp, Ro1, 0); // R.FP = f
+ cp = code;
+ br(Obne, 0); // CMPL ml->m->prog != 0
+
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Ro1, Rreg,O(REG,FP));
+ AIRR(Ostw, Rj, Rreg,O(REG,dt));
+ jmpl((ulong*)rmcall); // CALL rmcall
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Oblr); // RET
+
+ PATCH(cp);
+ AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Ostw, Ri, Rreg,O(REG,M));
+ AIRR(Oaddi, Ro2, Ro2, 1);
+ AIRR(Olwz, Rmp, Ri,O(Modlink,MP));
+ AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro2, Ri,O(Modlink,compiled));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ mtspr(Rctr, Rj);
+ gen(Obcctr | Cne); // return to compiled code
+
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ AIRR(Ostw, Rj, Rreg,O(REG,PC)); // R.PC = Rj
+ AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+ mtspr(Rlr, Rpic);
+ gen(Oblr); // return to xec uncompiled code
+}
+
+static void
+macmfra(void)
+{
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+ AIRR(Ostw, Ri, Rreg,O(REG,s));
+ AIRR(Ostw, Rj, Rreg,O(REG,d));
+ jmpl((ulong*)rmfram);
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Oblr);
+}
+
+static void
+macfram(void)
+{
+ ulong *cp;
+
+ /*
+ * Ri has t
+ */
+ AIRR(Olwz, Ro2, Ri,O(Type,size)); // MOVW t->size, Ro3
+ AIRR(Olwz, Ro1, Rreg,O(REG,SP)); // MOVW R.SP, Ro1 (=(Frame*)R.SP)
+ AIRR(Olwz, Ro3, Rreg,O(REG,TS)); // MOVW R.TS, tmp
+ ARRR(Oadd, Ro2, Ro2, Ro1); // ADD Ro1, t->size, nsp
+ ARRR(Ocmpl, Rcrf0, Ro2, Ro3); // CMPU nsp,tmp (nsp >= R.TS?)
+ cp = code;
+ br(Obge, 0); // BGE expand
+
+ AIRR(Olwz, Rj, Ri,O(Type,initialize));
+ mtspr(Rctr, Rj);
+ AIRR(Ostw, Ro2, Rreg,O(REG,SP)); // R.SP = nsp
+ AIRR(Ostw, Rzero, Ro1,O(Frame,mr)); // Ro1->mr = nil
+ AIRR(Ostw, Ri, Ro1,O(Frame,t)); // Ro1->t = t
+ gen(Obctr); // become t->init(Ro1), returning Ro1
+
+ PATCH(cp); // expand:
+ AIRR(Ostw, Ri, Rreg,O(REG,s)); // MOVL t, R.s
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st)); // MOVL Rlink, R.st
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // MOVL RFP, R.FP
+ jmpl((ulong*)extend); // CALL extend
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st)); // reload registers
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro1, Rreg,O(REG,s)); // return R.s set by extend
+ LRET(); // RET
+}
+
+static void
+movloop(int ldu, int stu, int adj)
+{
+ ulong *cp;
+
+ AIRR(Oaddi, Ro1, Ro1, -adj); // adjust for update ld/st
+ AIRR(Oaddi, Ro3, Ro3, -adj);
+ mtspr(Rctr, Ro2);
+
+ cp = code; // l0:
+ AIRR(ldu, Ri, Ro1,adj);
+ AIRR(stu, Ri, Ro3,adj);
+ br(Obc | Cdnz, ((ulong)cp-(ulong)code)); // DBNZ l0
+}
+
+static void
+movmem(Inst *i)
+{
+ ulong *cp;
+
+ // source address already in Ro1
+ if((i->add&ARM) != AXIMM){
+ op2(i, Olwz, Ro2);
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp = code;
+ br(Oble, 0);
+ opwst(i, Olea, Ro3);
+ movloop(Olbzu, Ostbu, 1);
+ PATCH(cp);
+ return;
+ }
+ switch(i->reg){
+ case 4:
+ AIRR(Olwz, Ro2, Ro1,0);
+ opwst(i, Ostw, Ro2);
+ break;
+ case 8:
+ AIRR(Olwz, Ro2, Ro1,0);
+ opwst(i, Olea, Ro3);
+ AIRR(Olwz, Ro1, Ro1,4);
+ AIRR(Ostw, Ro2, Ro3,0);
+ AIRR(Ostw, Ro1, Ro3,4);
+ break;
+ default:
+ // could use lwsi/stwsi loop...
+ opwst(i, Olea, Ro3);
+ if((i->reg&3) == 0) {
+ ldc(i->reg>>2, Ro2);
+ movloop(Olwzu, Ostwu, 4);
+ } else {
+ ldc(i->reg, Ro2);
+ movloop(Olbzu, Ostbu, 1);
+ }
+ break;
+ }
+}
+
+static void
+maccolr(void)
+{
+ ldbigc((ulong)&mutator, Ri);
+ AIRR(Olwz, Ri, Ri,0);
+ AIRR(Olwz, Ro3, Ro1,O(Heap,color)-sizeof(Heap)); // h->color
+
+ AIRR(Olwz, Ro2, Ro1,O(Heap,ref)-sizeof(Heap)); // h->ref
+
+ ARRR(Ocmp, Rcrf0, Ri, Ro3);
+ AIRR(Oaddi, Ro2, Ro2, 1); // h->ref++
+ AIRR(Ostw, Ro2, Ro1,O(Heap,ref)-sizeof(Heap));
+ gen(Obclr | Ceq); // return if h->color == mutator
+
+ ldc(propagator, Ro3);
+ AIRR(Ostw, Ro3, Ro1,O(Heap,color)-sizeof(Heap)); // h->color = propagator
+ ldc((ulong)&nprop, Ro3);
+ AIRR(Ostw, Ro1, Ro3,0); // nprop = !0
+ LRET();
+}
+
+static void
+maccvtfw(void)
+{
+ ulong *cp;
+
+ ARRR(Ofcmpo, Rcrf0, Rf1, Rfzero);
+ ARRR(Ofneg, Rf2, 0, Rfhalf);
+ cp = code;
+ br(Oblt, 0);
+ ARRR(Ofmr, Rf2, 0, Rfhalf);
+ PATCH(cp);
+ ARRR(Ofadd, Rf1, Rf1, Rf2); //x<0? x-.5: x+.5
+ ARRR(Ofctiwz, Rf2, 0, Rf1);
+ /* avoid using Ostfdu for now, since software emulation will run on same stack */
+ if(0){
+ AIRR(Ostfdu, Rf2, Rsp,-8); // MOVDU Rf2, -8(R1) (store in temp)
+ }else{
+ AIRR(Oaddi, Rsp, Rsp, -8); // SUB $8, R1
+ AIRR(Ostfd, Rf2, Rsp,0); // MOVD Rf2, 0(R1) (store in temp)
+ }
+ AIRR(Olwz, Ro1, Rsp,4); // MOVW 4(R1), Ro1
+ AIRR(Oaddi, Rsp, Rsp, 8); // ADD $8, R1
+ LRET();
+}
+
+static void
+macrelq(void)
+{
+ ARRR(Ocrxor, Rcrbrel, Rcrbrel, Rcrbrel); /* clear the relinquish condition */
+ mfspr(Rlink, Rlr);
+ IRR(Ostw, O(REG,FP),Rreg, Rfp);
+ IRR(Ostw, O(REG,PC),Rreg, Rlink);
+ IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+ jr(Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,dt));
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ mem(Olwz, j, Rfp, Ri);
+ jmpl(base+macro[MacFRP]);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ AIRR(Olwz, Rlink, Rreg,O(REG,dt));
+ mtspr(Rlr, Rlink);
+ gen(Oblr);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ ldc((ulong)H, Ri);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Ostw, j, Ro1, Ri);
+ j += sizeof(WORD*);
+ }
+ }
+ LRET();
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 3)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), ROMABLE);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = malloc(4096*sizeof(ulong));
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ if(code >= &tmp[4096]) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("tmp ovflo");
+ }
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ code = tmp;
+ (*macinit[i].f)();
+ macro[macinit[i].o] = n;
+ n += code - tmp;
+ }
+
+ base = mallocz((n+nlit)*sizeof(*base), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d ppc=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+ n = 0;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 3) {
+ print("%3d %D\n", i, &m->prog[i]);
+ while(s < code)
+ s += das(s);
+ }/**/
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ if(macro[macinit[i].o] != n) {
+ print("macinit %d\n", macinit[i].o);
+ urk("phase error");
+ }
+ s = code;
+ (*macinit[i].f)();
+ n += code - s;
+ if(cflag > 3) {
+ print("macinit %d\n", macinit[i].o);
+ while(s < code)
+ s += das(s);
+ }/**/
+ }
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(base+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(base+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(base+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(base);
+ free(tmp);
+ return 0;
+}
diff --git a/libinterp/comp-s800.c b/libinterp/comp-s800.c
new file mode 100644
index 00000000..90d8afc3
--- /dev/null
+++ b/libinterp/comp-s800.c
@@ -0,0 +1,2024 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define P4(o) ((o) < (1 << 4))
+#define N4(o) (~(o) < (1 << 4))
+#define P13(o) ((o) < (1 << 13))
+#define N13(o) (~(o) < (1 << 13))
+#define B4(o) ((o) & M4)
+#define B11(o) ((o) & M11)
+#define B13(o) ((o) & M13)
+#define B21(o) ((o) & M21)
+
+#define DOT ((ulong)code)
+#define RELPC(pc) ((ulong)(base+pc))
+
+#define nop() arith(Aor, RZ, RZ, RZ)
+#define bra(o) BL(RZ, (o))
+#define add(r, c) LDSTpos(Oldo, c, r, r)
+#define displ(ix) ((ulong)(base+patch[ix]-code-2))
+#define mdispl(ix) ((ulong)(base+macro[ix]-code-2))
+#define mbra(ix) bra(mdispl(ix))
+
+enum
+{
+ R0 = 0,
+ R1 = 1,
+ R2 = 2,
+
+ R19 = 19,
+ R20 = 20,
+ R21 = 21,
+ R22 = 22,
+ R23 = 23,
+ R24 = 24,
+ R25 = 25,
+ R26 = 26,
+ R27 = 27,
+ R28 = 28,
+ R29 = 29,
+ R30 = 30,
+ R31 = 31,
+
+ RLINK = R2, /* Function linkage */
+
+ RZ = R0, /* Always 0 */
+ RFP = R26, /* Frame Pointer */
+ RMP = R25, /* Module Pointer */
+ RREG = R24, /* Pointer to REG */
+ RTA = R29, /* Intermediate address for double indirect */
+ RCON = R23, /* Constant builder */
+ RCALL = R31, /* Call temp and link dest */
+
+ RA3 = R22, /* gpr 3 */
+ RA2 = R21, /* gpr 2 2+3 = big */
+ RA1 = R20, /* gpr 1 */
+ RA0 = R19, /* gpr 0 0+1 = big */
+
+ RCSP = R30, /* C stack pointer */
+ RARG0 = R26, /* C arg0 */
+ RMILLI0 = R22, /* Millicode arg0 */
+
+ /* Floating */
+ FRZ = 0, /* Zero */
+ FR0 = 4,
+ FR1 = 5,
+
+ /* opcodes */
+ Osys = 0x00,
+ Oarith = 0x02,
+ Oldwx = 0x03,
+ Oldil = 0x08,
+ Oldo = 0x0D,
+ Oldb = 0x10,
+ Oldh = 0x11,
+ Oldw = 0x12,
+ Ostb = 0x18,
+ Osth = 0x19,
+ Ostw = 0x1A,
+ Ocombt = 0x20,
+ Ocomibt = 0x21,
+ Ocombf = 0x22,
+ Ocomibf = 0x23,
+ Oaddibt = 0x29,
+ Oaddibf = 0x2B,
+ Oextrs = 0x34,
+ Obe = 0x38,
+ Oble = 0x39,
+ Obr = 0x3A,
+
+ Oflldst = 0x0B,
+ Ofltc = 0x0C,
+
+ Ftst = 0x2420,
+ Fload = 0,
+ Fstore = 1,
+
+ /* psuedo opcodes */
+ Pld = 0x10, /* base of loads */
+ Pst = 0x18, /* base of stores */
+
+ /* sub opcodes */
+ Aand = 0x10,
+ Aor = 0x12,
+ Axor = 0x14,
+ Asub = 0x20,
+ Aadd = 0x30,
+ Ash1add = 0x32,
+ Ash2add = 0x34,
+
+ /* FP sub codes */
+ Fadd = 0,
+ Fsub = 1,
+ Fmul = 2,
+ Fdiv = 3,
+
+ Sldsid = 0x85,
+ Smtsp = 0xC1,
+
+ /* conditions */
+ Cnever = 0,
+ Cequal = 1,
+ Cless = 2,
+ Cleq = 3,
+ Clessu = 4,
+ Clequ = 5,
+ Csv = 6,
+ Codd = 7,
+
+ /* FP conditions */
+ Fnever = 0,
+ Fequal = 1,
+ Fless = 2,
+ Fleq = 3,
+ Fgrt = 4,
+ Fgeq = 5,
+ Fneq = 6,
+ Falways = 7,
+
+ /* masks */
+ M4 = 0xF,
+ M5 = 0x1F,
+ M10 = 0x3FF,
+ M11 = 0x7FF,
+ M13 = 0x1FFF,
+ M21 = 0x1FFFFF,
+
+ /* spaces */
+ STemp = 0,
+ SCode = 4,
+ SData = 5,
+
+ PRESZ = 20,
+
+ /* punt ops */
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ NMACRO
+};
+
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(uchar*, int);
+extern ulong *dataptr;
+extern void calldata();
+extern void calltext();
+extern long dyncall;
+
+#define T(r) *((void**)(R.r))
+
+static void
+prlast()
+{
+ print("%x\t%x\n", code - 1, code[-1]);
+}
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+ char* name;
+} mactab[] =
+{
+ MacFRP, macfrp, "FRP", /* decrement and free pointer */
+ MacRET, macret, "RET", /* return instruction */
+ MacCASE, maccase, "CASE", /* case instruction */
+ MacCOLR, maccolr, "COLR", /* increment and color pointer */
+ MacMCAL, macmcal, "MCAL", /* mcall bottom half */
+ MacFRAM, macfram, "FRAM", /* frame instruction */
+ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static void
+urk(void)
+{
+ error("compile failed");
+}
+
+static int
+mkspace(int s)
+{
+ return ((s & 4) << 11) | ((s & 3) << 14);
+}
+
+static ulong
+posdisp(int disp)
+{
+ return (((disp & M10) << 1) | ((disp >> 10) & 1)) << 2;
+}
+
+static ulong
+disp11(int disp)
+{
+ return posdisp(disp) | (disp < 0 ? 1 : 0);
+}
+
+static void
+opatch(ulong *b)
+{
+ *b |= posdisp(code - b - 2);
+}
+
+static ulong
+frig17(ulong v)
+{
+ return ((v & M10) << 3) |
+ ((v & (1 << 10)) >> 8) |
+ ((v & (M5 << 11)) << 5) |
+ ((v >> 16) & 1);
+}
+
+static ulong
+frig21(ulong v)
+{
+ return ((v >> 20) & 1) |
+ ((v >> 8) & (M11 << 1)) |
+ ((v & 3) << 12) |
+ ((v & (3 << 7)) << 7) |
+ ((v & (M5 << 2)) << 14);
+}
+
+static void
+BLE(int r, int off, int s)
+{
+ *code++ = (Oble << 26) | (r << 21) | mkspace(s) | frig17(off >> 2);
+}
+
+static void
+BE(int r, int off, int s)
+{
+ *code++ = (Obe << 26) | (r << 21) | mkspace(s) | frig17(off);
+}
+
+static void
+BL(int r, int off)
+{
+ *code++ = (Obr << 26) | (r << 21) | frig17(off);
+}
+
+static void
+BV(int r)
+{
+ *code++ = (Obr << 26) | (r << 21) | (6 << 13);
+}
+
+static void
+LDIL(int r, ulong imm)
+{
+ *code++ = (Oldil << 26) | (r << 21) | frig21(imm);
+}
+
+static void
+LDWX(int i, int b, int r, int t)
+{
+ *code++ = (Oldwx << 26) | (b << 21) | (r << 16) | ((i - Pld) << 6) | t;
+}
+
+static void
+LDSTneg(int i, ulong off, int b, int r)
+{
+ *code++ = (i << 26) | (b << 21) | (r << 16) | (B13(off) << 1) | 1;
+}
+
+static void
+LDSTpos(int i, ulong off, int b, int r)
+{
+ *code++ = (i << 26) | (b << 21) | (r << 16) | (off << 1);
+}
+
+static void
+FLDSTneg(int inst, ulong disp, int rm, int r)
+{
+ *code++ = (Oflldst << 26) | (rm << 21) | (B4(disp) << 17) | (1 << 16) | (1 << 12) | (inst << 9) | r;
+}
+
+static void
+FLDSTpos(int inst, ulong disp, int rm, int r)
+{
+ *code++ = (Oflldst << 26) | (rm << 21) | (disp << 17) | (1 << 12) | (inst << 9) | r;
+}
+
+static void
+FLDSTX(int inst, int b, int x, int r)
+{
+ *code++ = (Oflldst << 26) | (b << 21) | (x << 17) | (inst << 9) | r;
+}
+
+static void
+FCMP(int r, int c, int b)
+{
+ *code++ = (Ofltc << 26) | (r << 21) | (b << 16) | (6 << 9) | (c << 2);
+}
+
+static void
+FTEST()
+{
+ *code++ = (Ofltc << 26) | Ftst;
+}
+
+static void
+farith(int o, int r1, int r2, int t)
+{
+ *code++ = (Ofltc << 26) | (r1 << 21) | (r2 << 16) | (o << 13) | (7 << 9) | t;
+}
+
+static void
+arith(int o, int s, int m, int d)
+{
+ *code++ = (Oarith << 26) | (m << 21) | (s << 16) | (o << 5) | d;
+}
+
+static void
+mov(int s, int d)
+{
+ LDSTpos(Oldo, 0, s, d);
+}
+
+static void
+shrs(int r, int s, int t)
+{
+ *code++ = (Oextrs << 26) | (r << 21) | (t << 16) | (7 << 10) | ((31 - s) << 5) | s;
+}
+
+static void
+comb(int op, int r1, int c, int r2, int off)
+{
+ *code++ = (op << 26) | (r2 << 21) | (r1 << 16) | (c << 13) | disp11(off);
+}
+
+static int
+es5(int v)
+{
+ return (B4(v) << 1) | (v < 0 ? 1 : 0);
+}
+
+static void
+combt(int r1, int c, int r2, int off)
+{
+ comb(Ocombt, r1, c, r2, off);
+}
+
+static void
+comibt(int r1, int c, int v, int off)
+{
+ comb(Ocomibt, es5(v), c, r1, off);
+}
+
+static void
+combf(int r1, int c, int r2, int off)
+{
+ comb(Ocombf, r1, c, r2, off);
+}
+
+static void
+comibf(int r1, int c, int v, int off)
+{
+ comb(Ocomibf, es5(v), c, r1, off);
+}
+
+static void
+combdis(int r1, int c, int r2, int f, int ix)
+{
+ comb(f ? Ocombf : Ocombt, r1, c, r2, displ(ix));
+}
+
+static void
+addibt(int r1, int c, int v, int off)
+{
+ comb(Oaddibt, es5(v), c, r1, off);
+}
+
+static void
+addibf(int r1, int c, int v, int off)
+{
+ comb(Oaddibf, es5(v), c, r1, off);
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+ if(opt) {
+ if(P13(o)) {
+ LDSTpos(Oldo, o, RZ, r);
+ return;
+ }
+ if(N13(o)) {
+ LDSTneg(Oldo, o, RZ, r);
+ return;
+ }
+ LDIL(r, B21(o >> 11));
+ if(B11(o) != 0)
+ LDSTpos(Oldo, B11(o), r, r);
+ }
+ else {
+ LDIL(r, B21(o >> 11));
+ LDSTpos(Oldo, B11(o), r, r);
+ }
+}
+
+static void
+call(ulong a, int s)
+{
+ if (s == SCode) {
+ con(a, RMILLI0, 1);
+ a = dyncall;
+ }
+ LDIL(RCALL, a >> 11);
+ BLE(RCALL, B11(a), s);
+ mov(RCALL, RLINK);
+}
+
+static void
+callindir(int r)
+{
+ BLE(r, 0, SData);
+ mov(RCALL, RLINK);
+}
+
+static void
+leafret()
+{
+ BV(RLINK);
+ nop();
+}
+
+static void
+linkage()
+{
+ LDSTneg(Ostw, -20, RCSP, RLINK);
+ LDSTpos(Oldo, 64, RCSP, RCSP);
+}
+
+static void
+ret()
+{
+ LDSTneg(Oldw, -84, RCSP, RLINK);
+ BV(RLINK);
+ LDSTneg(Oldo, -64, RCSP, RCSP);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+ if(P13(disp)) {
+ LDSTpos(inst, disp, rm, r);
+ return;
+ }
+ if(N13(disp)) {
+ LDSTneg(inst, disp, rm, r);
+ return;
+ }
+ con(disp, RCON, 1);
+ if(inst >= Pst) {
+ arith(Aadd, rm, RCON, RCON);
+ LDSTpos(inst, 0, RCON, r);
+ }
+ else
+ LDWX(inst, RCON, rm, r);
+}
+
+static void
+fmem(int inst, ulong disp, int rm, int r)
+{
+ if(P4(disp)) {
+ FLDSTpos(inst, disp, rm, r);
+ return;
+ }
+ if(N4(disp)) {
+ FLDSTneg(inst, disp, rm, r);
+ return;
+ }
+ con(disp, RCON, 1);
+ FLDSTX(inst, RCON, rm, r);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ mem(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ mem(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ con(i->s.imm, r, 1);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Oldo)
+ rta = r;
+ mem(Oldw, i->s.i.f, ir, rta);
+ mem(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(i->d.imm, r, 1);
+ return;
+ case DST(AFP):
+ mem(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ mem(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Oldo)
+ rta = r;
+ mem(Oldw, i->d.i.f, ir, rta);
+ mem(mi, i->d.i.s, rta, r);
+}
+
+static void
+opbig(Adr *a, int am, int mi, int r)
+{
+ int ir;
+
+ switch(am) {
+ default:
+ urk();
+ case AFP:
+ mem(mi, a->ind, RFP, r);
+ mem(mi, a->ind+4, RFP, r+1);
+ return;
+ case AMP:
+ mem(mi, a->ind, RMP, r);
+ mem(mi, a->ind+4, RMP, r+1);
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ mem(Oldw, a->i.f, ir, RTA);
+ mem(mi, a->i.s, RTA, r);
+ mem(mi, a->i.s+4, RTA, r+1);
+}
+
+static void
+opbigld(Inst *i, int r)
+{
+ opbig(&i->s, USRC(i->add), Oldw, r);
+}
+
+static void
+opbigst(Inst *i, int r)
+{
+ opbig(&i->d, UDST(i->add), Ostw, r);
+}
+
+static void
+opfloat(Adr *a, int am, int mi, int r)
+{
+ int ir;
+
+ switch(am) {
+ default:
+ urk();
+ case AFP:
+ fmem(mi, a->ind, RFP, r);
+ return;
+ case AMP:
+ fmem(mi, a->ind, RMP, r);
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ mem(Oldw, a->i.f, ir, RTA);
+ fmem(mi, a->i.s, RTA, r);
+}
+
+static void
+opflld(Inst *i, int r)
+{
+ opfloat(&i->s, USRC(i->add), Fload, r);
+}
+
+static void
+opflst(Inst *i, int r)
+{
+ opfloat(&i->d, UDST(i->add), Fstore, r);
+}
+
+static void
+midfl(Inst *i, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opfloat(&i->d, UDST(i->add), Fload, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ fmem(Fload, i->reg, ir, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ con((ulong)litpool, RTA, 0);
+ LDSTpos(Ostw, roff, RREG, RTA);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%d@%.8lux\n", R.M->m->name, *(ulong *)R.m, *(ulong *)R.s);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Oldo, RA0);
+ mem(Ostw, O(REG, s), RREG, RA0);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Oldo, RA0);
+ mem(Ostw, O(REG, d), RREG, RA0);
+ }
+
+ if(m & WRTPC) {
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Ostw, O(REG, PC), RREG, RA0);
+ }
+
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal(RELPC(pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ mem(Oldw, O(REG, d), RREG, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ mem(Oldo, i->reg, RFP, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ break;
+ case AXINM:
+ mem(Oldo, i->reg, RMP, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ break;
+ }
+
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ call((ulong)fn, SCode);
+
+ con((ulong)&R, RREG, 1);
+ if(m & TCHECK) {
+ mem(Oldw, O(REG, t), RREG, RA0);
+ combt(RA0, Cequal, RZ, 3);
+ nop();
+ mem(Oldw, O(REG, xpc), RREG, RLINK);
+ leafret();
+ }
+
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+
+ if(m & NEWPC) {
+ mem(Oldw, O(REG, PC), RREG, RA0);
+ BV(RA0);
+ nop();
+ }
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+}
+
+static void
+cbral(Inst *i, int jmsw, int fm, int jlsw, int fl, int mode)
+{
+ ulong dst, *label;
+
+ opwld(i, Oldo, RA1);
+ mid(i, Oldo, RA3);
+ mem(Oldw, 0, RA1, RA2);
+ mem(Oldw, 0, RA3, RA0);
+ label = nil;
+ dst = i->d.ins-mod->prog;
+ switch(mode) {
+ case ANDAND:
+ label = code;
+ comb(RA0, jmsw, RA2, fm, 0);
+ break;
+ case OROR:
+ combdis(RA0, jmsw, RA2, fm, dst);
+ break;
+ case EQAND:
+ combdis(RA0, jmsw, RA2, fm, dst);
+ nop();
+ label = code;
+ combf(RA0, Cequal, RA2, 0);
+ break;
+ }
+ nop();
+ mem(Oldw, 4, RA3, RA0);
+ mem(Oldw, 4, RA1, RA2);
+ combdis(RA0, jlsw, RA2, fl, dst);
+ if(label != nil)
+ opatch(label);
+}
+
+static void
+commcall(Inst *i)
+{
+ int o;
+
+ opwld(i, Oldw, RA2);
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Ostw, O(Frame, lr), RA2, RA0);
+ mem(Ostw, O(Frame, fp), RA2, RFP);
+ mem(Oldw, O(REG, M), RREG, RA3);
+ mem(Ostw, O(Frame, mr), RA2, RA3);
+ opwst(i, Oldw, RA3);
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc);
+ mem(Oldw, o, RA3, RA0);
+ call(base+macro[MacMCAL], SData);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RA0); // v
+ opwst(i, Oldo, RCON); // table
+ mbra(MacCASE);
+ nop();
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = RELPC(patch[t[2]]);
+ t += 3;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = RELPC(patch[t[4]]);
+ t += 6;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ ulong *punt, *mlnil;
+
+ opwld(i, Oldw, RA0);
+ mlnil = code;
+ comibt(RA0, Cequal, -1, 0);
+ nop();
+
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ mem(Oldw, o, RA0, RA3);
+ mem(Oldw, O(Type, initialize), RA3, RA1);
+ punt = code;
+ combf(RA1, Cequal, RZ, 0);
+ nop();
+
+ opwst(i, Oldo, RA0);
+
+ /* Type in RA3, destination in RA0 */
+ opatch(mlnil);
+ con(RELPC(patch[i-mod->prog+1]), RLINK, 0);
+ mbra(MacMFRA);
+ nop();
+
+ /* Type in RA3 */
+ opatch(punt);
+ call(base+macro[MacFRAM], SData);
+ opwst(i, Ostw, RA2);
+}
+
+static void
+movloop(Inst *i, int ld, int st)
+{
+ int s;
+
+ if(ld == Oldw)
+ s = 4;
+ else
+ s = 1;
+ opwld(i, Oldo, RA1);
+ opwst(i, Oldo, RA2);
+ mem(ld, 0, RA1, RA0);
+ mem(st, 0, RA2, RA0);
+ add(RA2, s);
+ addibf(RA3, Cequal, -1, -5);
+ add(RA1, s);
+}
+
+static void
+comp(Inst *i)
+{
+ int r, f;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMULW:
+ case IDIVW:
+ case IMODW:
+ case IMULB:
+ case IDIVB:
+ case IMODB:
+ case ISHRW:
+ case ISHLW:
+ case ISHRB:
+ case ISHLB:
+ case IADDL:
+ case ISUBL:
+ case IORL:
+ case IANDL:
+ case IXORL:
+ case ICVTWL:
+ case ISHLL:
+ case ISHRL:
+ case IINDX:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEW:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADM:
+ case IHEADB:
+ case IHEADW:
+ case IHEADL:
+ case IHEADF:
+ case IINDC:
+ case ILENC:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTFL:
+ case ICVTLF:
+ case ICVTWF:
+ case ICVTFW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ // comcase(i, 0);
+ // punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IGOTO:
+ opwld(i, Oldw, RA1);
+ opwst(i, Oldo, RA0);
+ arith(Ash2add, RA1, RZ, RA1);
+ LDWX(Oldw, RA0, RA1, RA0);
+ BV(RA0);
+ nop();
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = RELPC(patch[t[0]]);
+ t++;
+ }
+ break;
+ case IMOVL:
+ movl:
+ opbigld(i, RA0);
+ opbigst(i, RA0);
+ break;
+ case IMOVM:
+ if((i->add&ARM) == AXIMM) {
+ if(i->reg == 8)
+ goto movl;
+ if((i->reg&3) == 0) {
+ con(i->reg>>2, RA3, 1);
+ movloop(i, Oldw, Ostw);
+ break;
+ }
+ }
+ mid(i, Oldw, RA3);
+ movloop(i, Oldb, Ostb);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RA3, 1);
+ call(base+macro[MacFRAM], SData);
+ opwst(i, Ostw, RA2);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Oldb, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ILEA:
+ opwld(i, Oldo, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IMOVW:
+ opwld(i, Oldw, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IMOVB:
+ opwld(i, Oldb, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RA0);
+ mem(Oldw, O(List, tail), RA0, RA1);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RA1);
+ if(i->op == IHEADP)
+ mem(Oldw, OA(List, data), RA1, RA1);
+ movp:
+ comibt(RA1, Cequal, (ulong)H, 3); // H is small (-1)
+ nop();
+ call(base+macro[MacCOLR], SData); // 3 instrs
+ opwst(i, Oldw, RA0);
+ opwst(i, Ostw, RA1);
+ call(base+macro[MacFRP], SData);
+ break;
+ case ILENA:
+ opwld(i, Oldw, RA1);
+ comibt(RA1, Cequal, (ulong)H, 0);
+ mov(RZ, RA0);
+ mem(Oldw, O(Array, len), RA1, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ILENL:
+ mov(RZ, RA0);
+ opwld(i, Oldw, RA1);
+ comibt(RA1, Cequal, (ulong)H, 3);
+ nop();
+ mem(Oldw, O(List, tail), RA1, RA1);
+ bra(-5);
+ add(RA0, 1);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICALL:
+ opwld(i, Oldw, RA0);
+ con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+ mem(Ostw, O(Frame, lr), RA0, RA1);
+ mem(Ostw, O(Frame, fp), RA0, RFP);
+ bra(displ(i->d.ins-mod->prog));
+ mov(RA0, RFP);
+ break;
+ case IJMP:
+ bra(displ(i->d.ins-mod->prog));
+ nop();
+ break;
+ case IBEQW:
+ r = Cequal;
+ f = 0;
+ braw:
+ opwld(i, Oldw, RA0);
+ mid(i, Oldw, RA1);
+ combdis(RA0, r, RA1, f, i->d.ins-mod->prog);
+ nop();
+ break;
+ case IBNEW:
+ r = Cequal;
+ f = 1;
+ goto braw;
+ case IBLTW:
+ r = Cless;
+ f = 0;
+ goto braw;
+ case IBLEW:
+ r = Cleq;
+ f = 0;
+ goto braw;
+ case IBGTW:
+ r = Cleq;
+ f = 1;
+ goto braw;
+ case IBGEW:
+ r = Cless;
+ f = 1;
+ goto braw;
+ case IBEQB:
+ r = Cequal;
+ f = 0;
+ brab:
+ opwld(i, Oldb, RA0);
+ mid(i, Oldb, RA1);
+ combdis(RA0, r, RA1, f, i->d.ins-mod->prog);
+ nop();
+ break;
+ case IBNEB:
+ r = Cequal;
+ f = 1;
+ goto brab;
+ case IBLTB:
+ r = Cless;
+ f = 0;
+ goto brab;
+ case IBLEB:
+ r = Cleq;
+ f = 0;
+ goto brab;
+ case IBGTB:
+ r = Cleq;
+ f = 1;
+ goto brab;
+ case IBGEB:
+ r = Cless;
+ f = 1;
+ goto brab;
+ case IBEQF:
+ r = Fneq;
+ braf:
+ opflld(i, FR1);
+ midfl(i, FR0);
+ FCMP(FR1, r, FR0);
+ bra(displ(i->d.ins-mod->prog));
+ nop();
+ break;
+ case IBNEF:
+ r = Fequal;
+ goto braf;
+ case IBLTF:
+ r = Fgeq;
+ goto braf;
+ case IBLEF:
+ r = Fgrt;
+ goto braf;
+ case IBGTF:
+ r = Fleq;
+ goto braf;
+ case IBGEF:
+ r = Fless;
+ goto braf;
+ case IRET:
+ // punt(i, NEWPC, optab[i->op]);
+ mbra(MacRET);
+ mem(Oldw, O(Frame, t), RFP, RA1);
+ break;
+ case IORW:
+ r = Aor;
+ goto arithw;
+ case IANDW:
+ r = Aand;
+ goto arithw;
+ case IXORW:
+ r = Axor;
+ goto arithw;
+ case ISUBW:
+ r = Asub;
+ goto arithw;
+ case IADDW:
+ r = Aadd;
+ arithw:
+ mid(i, Oldw, RA1);
+ opwld(i, Oldw, RA0);
+ arith(r, RA1, RA0, RA1);
+ opwst(i, Ostw, RA1);
+ break;
+ case IORB:
+ r = Aor;
+ goto arithb;
+ case IANDB:
+ r = Aand;
+ goto arithb;
+ case IXORB:
+ r = Axor;
+ goto arithb;
+ case ISUBB:
+ r = Asub;
+ goto arithb;
+ case IADDB:
+ r = Aadd;
+ arithb:
+ mid(i, Oldb, RA1);
+ opwld(i, Oldb, RA0);
+ arith(r, RA1, RA0, RA1);
+ opwst(i, Ostb, RA1);
+ break;
+ case IINDL:
+ case IINDF:
+ case IINDW:
+ case IINDB:
+ opwld(i, Oldw, RA0); /* a */
+ r = 0;
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ r = 3;
+ break;
+ case IINDW:
+ r = 2;
+ break;
+ }
+ opwst(i, Oldw, RA1);
+ mem(Oldw, O(Array, data), RA0, RA0);
+ switch(r) {
+ default:
+ urk();
+ case 0:
+ arith(Aadd, RA0, RA1, RA0);
+ break;
+ case 2:
+ arith(Ash2add, RA1, RA0, RA0);
+ break;
+ case 3:
+ arith(Ash2add, RA1, RZ, RA1);
+ arith(Ash1add, RA1, RA0, RA0);
+ break;
+ }
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ mem(Ostw, i->reg, r, RA0);
+ break;
+ case ICVTLW:
+ opwld(i, Oldo, RA0);
+ mem(Oldw, 4, RA0, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IBEQL:
+ cbral(i, Cequal, 1, Cequal, 0, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Cequal, 1, Cequal, 1, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Cless, 0, Clequ, 0, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Cleq, 1, Clequ, 1, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Cless, 0, Clessu, 0, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Cleq, 1, Clessu, 1, EQAND);
+ break;
+ case IMOVF:
+ opflld(i, FR0);
+ opflst(i, FR0);
+ break;
+ case IDIVF:
+ r = Fdiv;
+ goto arithf;
+ case IMULF:
+ r = Fmul;
+ goto arithf;
+ case ISUBF:
+ r = Fsub;
+ goto arithf;
+ case IADDF:
+ r = Fadd;
+ arithf:
+ midfl(i, FR1);
+ opflld(i, FR0);
+ farith(r, FR1, FR0, FR1);
+ opflst(i, FR1);
+ break;
+ case INEGF:
+ opflld(i, FR0);
+ farith(Fsub, FRZ, FR0, FR0);
+ opflst(i, FR0);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+/*
+ * Preamble. This is complicated by the space registers.
+ * We point comvec at calldata which does a dataspace call
+ * to dataptr. The code at dataptr calls the real preamble
+ * code at start which saves the link register and branches
+ * to the new pc. When the compiled code finally returns
+ * by branching indirect through the saved link it will
+ * return into the dataptr code which will return to text
+ * space (calldata) which will return to the outside.
+ */
+static void
+preamble(void)
+{
+ ulong *start;
+
+ if (comvec)
+ return;
+
+ code = (ulong*)malloc(PRESZ * sizeof(*code));
+
+ if (code == nil)
+ urk();
+
+ start = code;
+ con((ulong)&R, RREG, 1); // load R
+ mem(Ostw, O(REG, xpc), RREG, RLINK); // save link
+ mem(Oldw, O(REG, PC), RREG, RA0); // load new PC
+ mem(Oldw, O(REG, FP), RREG, RFP); // load FP
+ BV(RA0); // jump to new PC
+ mem(Oldw, O(REG, MP), RREG, RMP); // load MP (delay)
+
+ dataptr = code;
+ LDSTneg(Ostw, -20, RCSP, RLINK); // save return link
+ LDSTpos(Oldo, 64, RCSP, RCSP); // stack frame
+ con((ulong)start, RA0, 1); // load start
+ BLE(RA0, 0, SData); // call real preamble
+ mov(RCALL, RLINK); // linkage (delay)
+ LDSTneg(Oldw, -84, RCSP, RLINK); // fetch return link
+ BE(RLINK, 0, SCode); // return to text space
+ LDSTneg(Oldo, -64, RCSP, RCSP); // stack frame (delay)
+
+ if (code > start + PRESZ)
+ error("preamble overrun");
+
+ segflush(start, PRESZ * sizeof(*code));
+
+ if(cflag > 4) {
+ print("preamble:\n");
+ das(start, code-start);
+ }
+
+ comvec = calldata;
+}
+
+static void
+maccase(void)
+{
+ ulong *loop, *def, *lab1;
+
+ mem(Oldw, 0, RCON, RA3); // n = t[0]
+ mem(Oldo, 4, RCON, RCON); // t = &t[1]
+ arith(Ash1add, RA3, RA3, RA1); // n1 = 3*n
+ arith(Ash2add, RA1, RZ, RA1); // n1 = 12*n
+ LDWX(Oldw, RCON, RA1, RLINK); // rlink = default
+
+ loop = code; // loop:
+ def = code;
+ combt(RA3, Cleq, RZ, 0); // if (n <= 0) goto out
+ // nop();
+
+ shrs(RA3, 1, RA2); // n' = n>>1
+ arith(Ash1add, RA2, RA2, RTA); // n2 = 3*n'
+ arith(Ash2add, RTA, RCON, RA1); // l = &t[n2]
+
+ mem(Oldw, 0, RA1, RTA); // l[0]
+ lab1 = code;
+ combt(RTA, Cleq, RA0, 0); // if (l[0] <= v) goto 1f
+ nop();
+ bra(loop-code-2); // goto loop
+ mov(RA2, RA3); // n = n2 (delay)
+
+ opatch(lab1); // 1f:
+ mem(Oldw, 4, RA1, RTA); // l[1]
+ lab1 = code;
+ combt(RA0, Cless, RTA, 0); // if (v < l[1]) goto 1f
+ nop();
+
+ mem(Oldo, 12, RA1, RCON); // t = &l[3]
+ arith(Asub, RA3, RA2, RA3); // n -= n'
+ bra(loop-code-2); // goto loop
+ mem(Oldo, -1, RA3, RA3); // n -= 1 (delay)
+
+ opatch(lab1); // 1f:
+ mem(Oldw, 8, RA1, RLINK); // rlink = l[2]
+
+ opatch(def); // out:
+ BV(RLINK); // jmp rlink
+ nop();
+}
+
+static void
+macfrp(void)
+{
+ ulong *lab1, *lab2;
+
+ /* destroy the pointer in RA0 */
+ lab1 = code;
+ comibt(RA0, Cequal, -1, 0); // if (p == h) goto out
+ nop();
+
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA0, RA2); // r = D2H(v)->ref
+ lab2 = code;
+ addibf(RA2, Cequal, -1, 0); // if (--r != 0) goto store
+ nop();
+
+ mem(Ostw, O(REG, FP), RREG, RFP); // call destroy
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, s), RREG, RA0);
+ call((ulong)rdestroy, SCode);
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ leafret();
+
+ opatch(lab2); // store
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ opatch(lab1); // out
+ leafret();
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+
+ cp1 = code;
+ combt(RA1, Cequal, RZ, 0); // if (t(Rfp) == 0) goto punt
+ nop();
+
+ mem(Oldw, O(Type, destroy), RA1, RA0);
+ cp2 = code;
+ combt(RA0, Cequal, RZ, 0); // if (destroy(t(fp)) == 0) goto punt
+ nop();
+
+ mem(Oldw, O(Frame, fp), RFP, RA2);
+ cp3 = code;
+ combt(RA2, Cequal, RZ, 0); // if (fp(Rfp) == 0) goto punt
+ nop();
+
+ mem(Oldw, O(Frame, mr), RFP, RA3);
+ cp4 = code;
+ combt(RA3, Cequal, RZ, 0); // if (mr(Rfp) == 0) goto call
+ nop();
+
+ mem(Oldw, O(REG, M), RREG, RA2);
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA2, RA3);
+ cp5 = code;
+ addibt(RA3, Cequal, -1, 0); // if (--ref(arg) == 0) goto punt
+ nop();
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA2, RA3);
+
+ mem(Oldw, O(Frame, mr), RFP, RA1);
+ mem(Ostw, O(REG, M), RREG, RA1);
+ mem(Oldw, O(Modlink, compiled), RA1, RA2); // check for uncompiled code
+ mem(Oldw, O(Modlink, MP), RA1, RMP);
+ cp6 = code;
+ combt(RA2, Cequal, RZ, 0);
+ nop();
+ mem(Ostw, O(REG, MP), RREG, RMP);
+
+ opatch(cp4);
+ callindir(RA0); // call destroy(t(fp))
+
+ mem(Ostw, O(REG, SP), RREG, RFP);
+ mem(Oldw, O(Frame, lr), RFP, RA1);
+ mem(Oldw, O(Frame, fp), RFP, RFP);
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ BV(RA1); // goto lr(Rfp)
+ mem(Oldw, O(Frame, fp), RFP, RFP); // (delay)
+
+ opatch(cp6);
+ callindir(RA0); // call destroy(t(fp))
+
+ mem(Ostw, O(REG, SP), RREG, RFP);
+ mem(Oldw, O(Frame, lr), RFP, RA1);
+ mem(Oldw, O(Frame, fp), RFP, RFP);
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, xpc), RREG, RA2);
+ BV(RA2); // return to uncompiled code
+ mem(Oldw, O(REG, PC), RREG, RA1);
+
+ opatch(cp1);
+ opatch(cp2);
+ opatch(cp3);
+ opatch(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ ulong *br;
+
+ /* color the pointer in RA1 */
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA1, RA0); // inc ref
+ add(RA0, 1);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ con((ulong)&mutator, RA2, 1);
+ mem(Oldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+ mem(Oldw, 0, RA2, RA2);
+ br = code;
+ combt(RA0, Cequal, RA2, 0); // if (color == mutator) goto out
+ con(propagator, RA2, 1);
+ mem(Ostw, O(Heap, color)-sizeof(Heap), RA1, RA2); // color = propagator
+ con((ulong)&nprop, RA2, 1);
+ mem(Ostw, 0, RA2, RA1); // nprop = !0
+ opatch(br);
+ leafret();
+}
+
+static void
+macmcal(void)
+{
+ ulong *lab1, *lab2;
+
+ mem(Oldw, O(Modlink, prog), RA3, RA1);
+ lab1 = code;
+ combf(RA1, Cequal, RZ, 0); // if (m->prog != nil) goto 1f
+ nop();
+
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, FP), RREG, RA2);
+ mem(Ostw, O(REG, dt), RREG, RA0);
+ call((ulong)rmcall, SCode); // CALL rmcall
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ leafret();
+
+ opatch(lab1); // 1f
+ mov(RA2, RFP);
+ mem(Ostw, O(REG, M), RREG, RA3);
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ add(RA1, 1);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ mem(Oldw, O(Modlink, compiled), RA3, RA1);
+ mem(Oldw, O(Modlink, MP), RA3, RMP);
+ lab2 = code;
+ combt(RA1, Cequal, RZ, 0);
+ mem(Ostw, O(REG, MP), RREG, RMP);
+
+ BV(RA0);
+ nop();
+
+ opatch(lab2);
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, xpc), RREG, RA1);
+ BV(RA1); // call to uncompiled code
+ mem(Ostw, O(REG, PC), RREG, RA0);
+}
+
+static void
+macfram(void)
+{
+ ulong *lab1;
+
+ mem(Oldw, O(REG, SP), RREG, RA0);
+ mem(Oldw, O(Type, size), RA3, RA1);
+ arith(Aadd, RA0, RA1, RA0); // new frame
+ mem(Oldw, O(REG, TS), RREG, RA1); // top of stack
+ lab1 = code;
+ combt(RA0, Cless, RA1, 0);
+ nop();
+
+ mem(Ostw, O(REG, s), RREG, RA3);
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ call((ulong)extend, SCode); // CALL extend
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, s), RREG, RA2);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ leafret();
+
+ opatch(lab1);
+ mem(Oldw, O(REG, SP), RREG, RA2); // old frame
+ mem(Ostw, O(REG, SP), RREG, RA0); // new frame
+
+ mem(Ostw, O(Frame, t), RA2, RA3); // f->t = t
+ mem(Oldw, O(Type, initialize), RA3, RA3);
+ BV(RA3); // initialize
+ mem(Ostw, O(Frame, mr), RA2, RZ); // f->mr = nil
+}
+
+static void
+macmfra(void)
+{
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, s), RREG, RA3); // save type
+ mem(Ostw, O(REG, d), RREG, RA0); // save destination
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ call((ulong)rmfram, SCode); // call rmfram
+
+ con((ulong)&R, RREG, 1); // reload
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ BV(RLINK);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+ ulong frp;
+
+ frp = (ulong)(base+macro[MacFRP]);
+ mem(Ostw, O(REG, dt), RREG, RLINK);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ mem(Oldw, j, RFP, RA0);
+ call(frp, SData);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ mem(Oldw, O(REG, dt), RREG, RLINK);
+ leafret();
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RA0, 1);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Ostw, j, RA2, RA0);
+ j += sizeof(WORD*);
+ }
+ }
+ leafret();
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong tmp[4096], *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ if (code - start != n / sizeof(*code))
+ error("typecom mismatch");
+
+ segflush(start, n);
+
+ if(cflag > 1)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ ulong v;
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, tmp[4096];
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ if(tinit == nil || patch == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ base = mallocz((n + nlit) * sizeof(ulong), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 1)
+ print("dis=%5d %5d s800=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = (ulong*)base + n;
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 2) {
+ print("%D\n", &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ s = code;
+ mactab[i].gen();
+ if(cflag > 2) {
+ print("%s:\n", mactab[i].name);
+ das(s, code-s);
+ }
+ }
+
+ if (code - base != n)
+ error("typecom mismatch");
+
+ segflush(base, n * sizeof(*base));
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+ if(cflag > 2)
+ print("entry %lx\n", m->entry);
+ free(patch);
+ free(tinit);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(base);
+ return 0;
+}
diff --git a/libinterp/comp-sparc.c b/libinterp/comp-sparc.c
new file mode 100644
index 00000000..f6ca2aa6
--- /dev/null
+++ b/libinterp/comp-sparc.c
@@ -0,0 +1,1882 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+enum
+{
+ R8 = 8, /* SUN calls these %o0 - %o7 */
+ R9 = 9,
+ R10 = 10,
+ R11 = 11,
+ R12 = 12,
+ R13 = 13,
+ R14 = 14, /* SUN %sp */
+ R15 = 15, /* R15/%o7 is the default link register */
+
+ R16 = 16, /* SUN calls these %l0 - %l7 */
+ R17 = 17,
+ R18 = 18,
+ R19 = 19,
+ R20 = 20,
+ R21 = 21,
+ R22 = 22,
+ R23 = 23,
+ RLINK = 15,
+
+ RZ = 0, /* Always 0 */
+ RFP = R23, /* Frame Pointer */
+ RMP = R22, /* Module Pointer */
+ RTA = R21, /* Intermediate address for double indirect */
+ RREG = R20, /* Pointer to REG */
+ RA3 = R19, /* gpr 3 */
+ RA2 = R18, /* gpr 2 2+3 = L */
+ RA1 = R17, /* gpr 1 */
+ RA0 = R16, /* gpr 0 0+1 = L */
+
+ RCON = R8, /* Constant builder */
+
+ FA2 = 2, /* Floating */
+ FA3 = 3,
+ FA4 = 4,
+ FA5 = 5,
+
+ Olea = (1<<20), /* Pseudo op */
+ Owry = 48,
+ Omul = 11,
+ Oumul = 10,
+ Osdiv = 15,
+ Osll = 37,
+ Osra = 39,
+ Osrl = 38,
+ Osethi = 4,
+ Oadd = 0,
+ Oaddcc = 16,
+ Oaddx = 8,
+ Osub = 4,
+ Osubcc = 20,
+ Osubx = 12,
+ Oor = 2,
+ Oand = 1,
+ Oxor = 3,
+ Oldw = 0,
+ Oldsh = 10,
+ Ostw = 4,
+ Osth = 6,
+ Ojmpl = 56,
+ Ocall = 1,
+ Ocmp = 20, /* subcc */
+ Oldbu = 1,
+ Ostb = 5,
+ Oba = 8,
+ Obn = 0,
+ Obne = 9,
+ Obe = 1,
+ Obg = 10,
+ Oble = 2,
+ Obge = 11,
+ Obl = 3,
+ Obgu = 12,
+ Obleu = 4,
+ Obcc = 13,
+ Obcs = 5,
+ Obpos = 14,
+ Obneg = 6,
+ Obvc = 15,
+ Obvs = 7,
+ OfaddD = 66,
+ OfsubD = 70,
+ OfdivD = 78,
+ OfmulD = 74,
+ Oldf = 32,
+ Ostf = 36,
+ OfDtoQ = 206,
+ OfnegS = 5,
+ OfcmpD = 82,
+ Ofba = 8,
+ Ofbe = 9,
+ Ofbg = 6,
+ Ofbge = 11,
+ Ofbl = 4,
+ Ofble = 13,
+ Ofbne = 1,
+ OfWtoD = 200,
+ OfDtoW = 210,
+ Osave = 60,
+ Orestore= 61,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ NMACRO
+};
+
+#define OP(n) (n<<30)
+#define I13(i) ((i)&0x1fff)
+#define D22(i) ((i)&0x3fffff)
+#define PC30(pc) (((ulong)(pc) - (ulong)code)>>2)
+
+#define CALL(addr) *code=OP(1)|PC30(addr); code++
+#define FM2I(op2, i, rd) *code=OP(0)|(rd<<25)|(op2<<22)|D22(i); code++
+#define BRA(cond, disp) *code=OP(0)|(cond<<25)|(2<<22)|D22((disp)); code++
+#define BRAF(cond, disp) *code=OP(0)|(cond<<25)|(6<<22)|D22((disp)); code++
+#define BRADIS(r, o) BRA(r, ((ulong)(base+patch[o])-(ulong)code)>>2)
+#define BRAFDIS(r, o) BRAF(r, ((ulong)(base+patch[o])-(ulong)code)>>2)
+#define BRAMAC(r, o) BRA(r, ((ulong)(base+macro[o])-(ulong)code)>>2);
+#define FM3I(op, op3, i, rs1, rd) *code++=OP(op)|(rd<<25)|(op3<<19)|(rs1<<14)|\
+ (1<<13)|I13(i)
+#define FM3(op, op3, rs2, rs1, rd) *code++=OP(op)|(rd<<25)|(op3<<19)|(rs1<<14)|rs2
+#define FMF1(opf, rs2, rs1, rd) *code++=OP(2)|(rd<<25)|(52<<19)|(rs1<<14)|(opf<<5)|rs2
+#define FMF2(opf, rs2, rs1, rd) *code++=OP(2)|(rd<<25)|(53<<19)|(rs1<<14)|(opf<<5)|rs2
+#define NOOP *code++=(4<<22)
+#define RETURN FM3I(2, Ojmpl, 8, RLINK, RZ);
+#define MOV(s, d) FM3(2, Oor, s, RZ, d)
+
+#define RELPC(pc) (ulong)(base+pc)
+#define PATCH(ptr) *ptr |= (code-ptr) & 0x3fffff
+
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static int puntpc = 1;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(ulong*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+ char* name;
+} mactab[] =
+{
+ MacFRP, macfrp, "FRP", /* decrement and free pointer */
+ MacRET, macret, "RET", /* return instruction */
+ MacCASE, maccase, "CASE", /* case instruction */
+ MacCOLR, maccolr, "COLR", /* increment and color pointer */
+ MacMCAL, macmcal, "MCAL", /* mcall bottom half */
+ MacFRAM, macfram, "FRAM", /* frame instruction */
+ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ if(R.d == H)
+ error(exModule);
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static void
+urk(void)
+{
+ error(exCompile);
+}
+
+static int
+bc(long c)
+{
+ c &= ~0xfffL;
+ if (c == 0 || c == ~0xfffL)
+ return 1;
+
+ return 0;
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+ if(opt != 0) {
+ if(bc(o)) {
+ FM3I(2, Oadd, o & 0x1fff, RZ, r);
+ return;
+ }
+ if((o & 0x3ff) == 0) {
+ FM2I(Osethi, o>>10, r);
+ return;
+ }
+ }
+ FM2I(Osethi, o>>10, r);
+ FM3I(2, Oadd, o & 0x3ff, r, r);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+ int op;
+
+ op = 3;
+ if(inst == Olea) {
+ op = 2;
+ inst = Oadd;
+ }
+ if(bc(disp)) {
+ FM3I(op, inst, disp, rm, r);
+ return;
+ }
+ con(disp, RCON, 1);
+ FM3(op, inst, RCON, rm, r);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ mem(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ mem(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ con(i->s.imm, r, 1);
+ if(mi == Olea) {
+ mem(Ostw, O(REG, st), RREG, r);
+ con((ulong)&R.st, r, 1);
+ }
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ mem(Oldw, i->s.i.f, ir, rta);
+ mem(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(i->d.imm, r, 1);
+ return;
+ case DST(AFP):
+ mem(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ mem(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ mem(Oldw, i->d.i.f, ir, rta);
+ mem(mi, i->d.i.s, rta, r);
+}
+
+static void
+opfl(Adr *a, int am, int mi, int r)
+{
+ int ir;
+
+ switch(am) {
+ default:
+ urk();
+ case AFP:
+ mem(mi, a->ind, RFP, r);
+ mem(mi, a->ind+4, RFP, r+1);
+ return;
+ case AMP:
+ mem(mi, a->ind, RMP, r);
+ mem(mi, a->ind+4, RMP, r+1);
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ mem(Oldw, a->i.f, ir, RTA);
+ mem(mi, a->i.s, RTA, r);
+ mem(mi, a->i.s+4, RTA, r+1);
+}
+
+static void
+opflld(Inst *i, int mi, int r)
+{
+ opfl(&i->s, USRC(i->add), mi, r);
+}
+
+static void
+opflst(Inst *i, int mi, int r)
+{
+ opfl(&i->d, UDST(i->add), mi, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ con((ulong)litpool, RTA, 0);
+ mem(Ostw, roff, RREG, RTA);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, RA0);
+ mem(Ostw, O(REG, s), RREG, RA0);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Olea, RA0);
+ mem(Ostw, O(REG, d), RREG, RA0);
+ }
+ if(m & WRTPC) {
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Ostw, O(REG, PC), RREG, RA0);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal(RELPC(pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ mem(Oldw, O(REG, d), RREG, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ mem(Olea, i->reg, RFP, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ break;
+ case AXINM:
+ mem(Olea, i->reg, RMP, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ break;
+ }
+
+ CALL(fn);
+ mem(Ostw, O(REG, FP), RREG, RFP);
+
+ con((ulong)&R, RREG, 1);
+ if(m & TCHECK) {
+ mem(Oldw, O(REG, t), RREG, RA0);
+ FM3I(2, Ocmp, 0, RA0, RZ);
+ BRA(Obe, 5);
+ NOOP;
+ mem(Oldw, O(REG, xpc), RREG, RLINK);
+ RETURN;
+ NOOP;
+ }
+
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+
+ if(m & NEWPC) {
+ mem(Oldw, O(REG, PC), RREG, RA0);
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ NOOP;
+ }
+}
+
+static void
+midfl(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opflst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+ mem(mi, i->reg+4, ir, r+1);
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst, *label;
+
+ opwld(i, Olea, RA1);
+ mid(i, Olea, RA3);
+ mem(Oldw, 0, RA1, RA2);
+ mem(Oldw, 0, RA3, RA0);
+ FM3(2, Ocmp, RA0, RA2, RZ);
+ label = nil;
+ dst = i->d.ins-mod->prog;
+ switch(mode) {
+ case ANDAND:
+ label = code;
+ BRA(jmsw, 0);
+ break;
+ case OROR:
+ BRADIS(jmsw, dst);
+ break;
+ case EQAND:
+ BRADIS(jmsw, dst);
+ NOOP;
+ label = code;
+ BRA(Obne, 0);
+ break;
+ }
+ NOOP;
+ mem(Oldw, 4, RA3, RA0);
+ mem(Oldw, 4, RA1, RA2);
+ FM3(2, Ocmp, RA0, RA2, RZ);
+ BRADIS(jlsw, dst);
+ if(label != nil)
+ PATCH(label);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RA0); // v
+ opwst(i, Olea, RCON); // table
+ BRAMAC(Oba, MacCASE);
+ NOOP;
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = RELPC(patch[t[2]]);
+ t += 3;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = RELPC(patch[t[4]]);
+ t += 6;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ ulong *punt, *mlnil;
+
+ opwld(i, Oldw, RA0);
+ FM3I(2, Ocmp, -1, RA0, RZ);
+ mlnil = code;
+ BRA(Obe, 0);
+ NOOP;
+
+ if((i->add&ARM) == AXIMM) {
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ mem(Oldw, o, RA0, RA3);
+ } else {
+ mid(i, Oldw, RA1);
+ FM3I(2, Osll, 3, RA1, RA1); // assumes sizeof(Modl) == 8
+ FM3(2, Oadd, RA0, RA1, RA1);
+ o = OA(Modlink, links)+O(Modl, frame);
+ mem(Oldw, o, RA1, RA3);
+ }
+ mem(Oldw, O(Type, initialize), RA3, RA1);
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ punt = code;
+ BRA(Obne, 0);
+ NOOP;
+
+ opwst(i, Olea, RA0);
+
+ /* Type in RA3, destination in RA0 */
+ PATCH(mlnil);
+ con(RELPC(patch[i-mod->prog+1])-8, RLINK, 0);
+ BRAMAC(Oba, MacMFRA);
+ NOOP;
+
+ /* Type in RA3 */
+ PATCH(punt);
+ CALL(base+macro[MacFRAM]);
+ NOOP;
+ opwst(i, Ostw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+ opwld(i, Oldw, RA2);
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Ostw, O(Frame, lr), RA2, RA0);
+ mem(Ostw, O(Frame, fp), RA2, RFP);
+ mem(Oldw, O(REG, M), RREG, RA3);
+ mem(Ostw, O(Frame, mr), RA2, RA3);
+ opwst(i, Oldw, RA3);
+ if((i->add&ARM) == AXIMM) {
+ CALL(base+macro[MacMCAL]);
+ mem(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+ } else {
+ mid(i, Oldw, RA1);
+ FM3I(2, Osll, 3, RA1, RA1); // assumes sizeof(Modl) == 8
+ FM3(2, Oadd, RA1, RA3, RA0);
+ CALL(base+macro[MacMCAL]);
+ mem(Oldw, OA(Modlink, links)+O(Modl, u.pc), RA0, RA0);
+ }
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opflld(i, Oldw, RA0);
+ midfl(i, Oldw, RA2);
+ FM3(2, op, RA1, RA3, RA1);
+ FM3(2, opc, RA0, RA2, RA0);
+ opflst(i, Ostw, RA0);
+}
+
+static void
+movloop(Inst *i, int ld, int st)
+{
+ int s;
+
+ s = 1;
+ if(ld == Oldw)
+ s = 4;
+ opwld(i, Olea, RA1);
+ opwst(i, Olea, RA2);
+ mem(ld, 0, RA1, RA0);
+ mem(st, 0, RA2, RA0);
+ FM3I(2, Oadd, s, RA2, RA2);
+ FM3I(2, Oaddcc, -1, RA3, RA3);
+ BRA(Obne, -4);
+ FM3I(2, Oadd, s, RA1, RA1);
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%d@%.8ux\n", R.M->m->name, R.t, R.st);
+}
+
+static void
+shll(Inst *i)
+{
+ ulong *lab0, *lab1, *lab2;
+
+ opwld(i, Oldw, RA2);
+ midfl(i, Oldw, RA0);
+ FM3I(2, Ocmp, RZ, RA2, RZ);
+ lab0 = code;
+ BRA(Obe, 0);
+ FM3I(2, Ocmp, 32, RA2, RZ);
+ lab1 = code;
+ BRA(Obl, 0);
+ NOOP;
+ FM3I(2, Osub, 32, RA2, RA2);
+ FM3(2, Osll, RA2, RA1, RA0);
+ lab2 = code;
+ BRA(Oba, 0);
+ MOV(RZ, RA1);
+
+ PATCH(lab1);
+ FM3(2, Osll, RA2, RA0, RA0);
+ con(32, RA3, 1);
+ FM3(2, Osub, RA2, RA3, RA3);
+ FM3(2, Osrl, RA3, RA1, RA3);
+ FM3(2, Oor, RA0, RA3, RA0);
+ FM3(2, Osll, RA2, RA1, RA1);
+
+ PATCH(lab0);
+ PATCH(lab2);
+ opflst(i, Ostw, RA0);
+}
+
+static void
+comp(Inst *i)
+{
+ int r;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ puntpc = 0;
+ punt(&xx, SRCOP, compdbg);
+ puntpc = 1;
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMODW:
+ case IMODB:
+ case IMNEWZ:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADM:
+ case IHEADB:
+ case IHEADW:
+ case IHEADL:
+ case IHEADF:
+ case IINDC:
+ case ILENC:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IGOTO:
+ opwld(i, Oldw, RA1);
+ opwst(i, Olea, RA0);
+ FM3I(2, Osll, 2, RA1, RA1);
+ FM3(3, Oldw, RA1, RA0, RA0);
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ NOOP;
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = RELPC(patch[t[0]]);
+ t++;
+ }
+ break;
+ case IMOVL:
+ movl:
+ opflld(i, Oldw, RA0);
+ opflst(i, Ostw, RA0);
+ break;
+ case IMOVM:
+ if((i->add&ARM) == AXIMM) {
+ if(i->reg == 8)
+ goto movl;
+ if((i->reg&3) == 0) {
+ con(i->reg>>2, RA3, 1);
+ movloop(i, Oldw, Ostw);
+ break;
+ }
+ }
+ mid(i, Oldw, RA3);
+ movloop(i, Oldbu, Ostb);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RA3, 1);
+ CALL(base+macro[MacFRAM]);
+ NOOP;
+ opwst(i, Ostw, RA2);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Oldbu, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ILEA:
+ opwld(i, Olea, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IMOVW:
+ opwld(i, Oldw, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IMOVB:
+ opwld(i, Oldbu, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ICVTSW:
+ opwld(i, Oldsh, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICVTWS:
+ opwld(i, Oldw, RA0);
+ opwst(i, Osth, RA0);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RA0);
+ mem(Oldw, O(List, tail), RA0, RA1);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RA1);
+ if(i->op == IHEADP)
+ mem(Oldw, OA(List, data), RA1, RA1);
+ movp:
+ FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+ BRA(Obe, 5);
+ con((ulong)&mutator, RA2, 1);
+ CALL(base+macro[MacCOLR]);
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ opwst(i, Oldw, RA0);
+ opwst(i, Ostw, RA1);
+ CALL(base+macro[MacFRP]);
+ NOOP;
+ break;
+ case ILENA:
+ opwld(i, Oldw, RA1);
+ FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+ BRA(Obe, 3);
+ con(0, RA0, 1);
+ mem(Oldw, O(Array, len), RA1, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ILENL:
+ con(0, RA0, 1);
+ opwld(i, Oldw, RA1);
+ FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+ BRA(Obe, 5);
+ NOOP;
+ mem(Oldw, O(List, tail), RA1, RA1);
+ BRA(Oba, -4);
+ FM3I(2, Oadd, 1, RA0, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICALL:
+ opwld(i, Oldw, RA0);
+ con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+ mem(Ostw, O(Frame, lr), RA0, RA1);
+ mem(Ostw, O(Frame, fp), RA0, RFP);
+ BRADIS(Oba, i->d.ins-mod->prog);
+ MOV(RA0, RFP);
+ break;
+ case IJMP:
+ BRADIS(Oba, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBEQW:
+ r = Obe;
+ braw:
+ opwld(i, Oldw, RA1);
+ mid(i, Oldw, RA0);
+ FM3(2, Ocmp, RA0, RA1, RZ);
+ BRADIS(r, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBNEW:
+ r = Obne;
+ goto braw;
+ case IBLTW:
+ r = Obl;
+ goto braw;
+ case IBLEW:
+ r = Oble;
+ goto braw;
+ case IBGTW:
+ r = Obg;
+ goto braw;
+ case IBGEW:
+ r = Obge;
+ goto braw;
+ case IBEQB:
+ r = Obe;
+ brab:
+ opwld(i, Oldbu, RA1);
+ mid(i, Oldbu, RA0);
+ FM3(2, Ocmp, RA0, RA1, RZ);
+ BRADIS(r, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBNEB:
+ r = Obne;
+ goto brab;
+ case IBLTB:
+ r = Obl;
+ goto brab;
+ case IBLEB:
+ r = Oble;
+ goto brab;
+ case IBGTB:
+ r = Obg;
+ goto brab;
+ case IBGEB:
+ r = Obge;
+ goto brab;
+ case IBEQF:
+ r = Ofbe;
+ braf:
+ opflld(i, Oldf, FA4);
+ midfl(i, Oldf, FA2);
+ FMF2(OfcmpD, FA2, FA4, 0);
+ NOOP;
+ BRAFDIS(r, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBNEF:
+ r = Ofbne;
+ goto braf;
+ case IBLTF:
+ r = Ofbl;
+ goto braf;
+ case IBLEF:
+ r = Ofble;
+ goto braf;
+ case IBGTF:
+ r = Ofbg;
+ goto braf;
+ case IBGEF:
+ r = Ofbge;
+ goto braf;
+ case IRET:
+ BRAMAC(Oba, MacRET);
+ mem(Oldw, O(Frame,t), RFP, RA1);
+ break;
+ case IORW:
+ r = Oor;
+ goto arithw;
+ case IANDW:
+ r = Oand;
+ goto arithw;
+ case IXORW:
+ r = Oxor;
+ goto arithw;
+ case ISUBW:
+ r = Osub;
+ goto arithw;
+ case ISHRW:
+ r = Osra;
+ goto arithw;
+ case ISHLW:
+ r = Osll;
+ goto arithw;
+ case ILSRW:
+ r = Osrl;
+ goto arithw;
+ case IMULW:
+ r = Omul;
+ goto arithw;
+ case IDIVW:
+ r = Osdiv;
+ goto arithw;
+ case IADDW:
+ r = Oadd;
+ arithw:
+ mid(i, Oldw, RA1);
+ if(i->op == IDIVW) {
+ FM3I(2, Osra, 31, RA1, RA0);
+ FM3(2, Owry, RZ, RA0, 0);
+ }
+ if(UXSRC(i->add) == SRC(AIMM) && bc(i->s.imm))
+ FM3I(2, r, i->s.imm, RA1, RA0);
+ else {
+ opwld(i, Oldw, RA0);
+ FM3(2, r, RA0, RA1, RA0);
+ }
+ opwst(i, Ostw, RA0);
+ break;
+ case IORB:
+ r = Oor;
+ goto arithb;
+ case IANDB:
+ r = Oand;
+ goto arithb;
+ case IXORB:
+ r = Oxor;
+ goto arithb;
+ case ISUBB:
+ r = Osub;
+ goto arithb;
+ case IMULB:
+ r = Omul;
+ goto arithb;
+ case IDIVB:
+ FM3(2, Owry, RZ, RZ, 0);
+ r = Osdiv;
+ goto arithb;
+ case IADDB:
+ r = Oadd;
+ arithb:
+ mid(i, Oldbu, RA1);
+ opwld(i, Oldbu, RA0);
+ FM3(2, r, RA0, RA1, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ISHRB:
+ r = Osra;
+ goto shiftb;
+ case ISHLB:
+ r = Osll;
+ shiftb:
+ mid(i, Oldbu, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && bc(i->s.imm))
+ FM3I(2, r, i->s.imm, RA1, RA0);
+ else {
+ opwld(i, Oldw, RA0);
+ FM3(2, r, RA0, RA1, RA0);
+ }
+ opwst(i, Ostb, RA0);
+ break;
+ case IINDL:
+ case IINDF:
+ case IINDW:
+ case IINDB:
+ opwld(i, Oldw, RA0); /* a */
+ r = 0;
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ r = 3;
+ break;
+ case IINDW:
+ r = 2;
+ break;
+ }
+ if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<<r)) {
+ mem(Oldw, O(Array, data), RA0, RA0);
+ FM3I(2, Oadd, (i->d.imm<<r), RA0, RA0);
+ }
+ else {
+ opwst(i, Oldw, RA1);
+ mem(Oldw, O(Array, data), RA0, RA0);
+ if(r != 0)
+ FM3I(2, Osll, r, RA1, RA1);
+ FM3(2, Oadd, RA0, RA1, RA0);
+ }
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ mem(Ostw, i->reg, r, RA0);
+ break;
+ case IINDX:
+ opwld(i, Oldw, RA0); /* a */
+ /*
+ r = 0;
+ if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<<r))
+ r = i->d.imm<<r;
+ else
+ */
+ opwst(i, Oldw, RA1); /* i */
+ mem(Oldw, O(Array, t), RA0, RA2);
+ mem(Oldw, O(Array, data), RA0, RA0);
+ mem(Oldw, O(Type, size), RA2, RA2);
+ /*
+ if(r != 0)
+ FM3I(2, Oumul, r, RA2, RA1);
+ else
+ */
+ FM3(2, Oumul, RA1, RA2, RA1);
+ FM3(2, Oadd, RA0, RA1, RA0);
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ mem(Ostw, i->reg, r, RA0);
+ break;
+ case IADDL:
+ larith(i, Oaddcc, Oaddx);
+ break;
+ case ISUBL:
+ larith(i, Osubcc, Osubx);
+ break;
+ case IORL:
+ larith(i, Oor, Oor);
+ break;
+ case IANDL:
+ larith(i, Oand, Oand);
+ break;
+ case IXORL:
+ larith(i, Oxor, Oxor);
+ break;
+ case ICVTWL:
+ opwld(i, Oldw, RA1);
+ FM3I(2, Osra, 31, RA1, RA0);
+ opflst(i, Ostw, RA0);
+ break;
+ case ICVTLW:
+ opwld(i, Olea, RA0);
+ mem(Oldw, 4, RA0, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IBEQL:
+ cbral(i, Obne, Obe, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, Obne, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Obl, Obleu, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Obg, Obgu, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Obl, Obcs, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Obg, Obcc, EQAND);
+ break;
+ case IMOVF:
+ opflld(i, Oldf, FA2);
+ opflst(i, Ostf, FA2);
+ break;
+ case IDIVF:
+ r = OfdivD;
+ goto arithf;
+ case IMULF:
+ r = OfmulD;
+ goto arithf;
+ case ISUBF:
+ r = OfsubD;
+ goto arithf;
+ case IADDF:
+ r = OfaddD;
+ arithf:
+ opflld(i, Oldf, FA2);
+ midfl(i, Oldf, FA4);
+ FMF1(r, FA2, FA4, FA4);
+ opflst(i, Ostf, FA4);
+ break;
+ case INEGF:
+ opflld(i, Oldf, FA2);
+ FMF1(OfnegS, FA2, 0, FA2);
+ opflst(i, Ostf, FA2);
+ break;
+ case ICVTFL:
+ // >= Sparc 8
+ // opflld(i, Oldf, FA2);
+ // FMF1(OfDtoQ, FA2, 0, FA2);
+ // opflst(i, Ostf, FA2);
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICVTLF:
+ // >= Sparc 8
+ // opflld(i, Oldf, FA2);
+ // FMF1(OfQtoD, FA2, 0, FA2);
+ // opflst(i, Ostf, FA2);
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICVTWF:
+ opwld(i, Oldf, FA2);
+ FMF1(OfWtoD, FA2, 0, FA2);
+ opflst(i, Ostf, FA2);
+ break;
+ case ICVTFW:
+ opflld(i, Oldf, FA2);
+ FMF1(OfDtoW, FA2, 0, FA2);
+ opwst(i, Ostf, FA2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ ulong *start;
+
+ if(comvec)
+ return;
+
+ comvec = malloc(10 * sizeof(*code));
+ if(comvec == nil)
+ error(exNomem);
+ code = (ulong*)comvec;
+ start = code;
+
+ con((ulong)&R, RREG, 1);
+ mem(Ostw, O(REG, xpc), RREG, RLINK);
+ mem(Oldw, O(REG, PC), RREG, RA0);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+
+ segflush(comvec, 10 * sizeof(*code));
+
+ if(cflag > 4) {
+ print("comvec:\n");
+ das(start, code-start);
+ }
+}
+
+static void
+maccase(void)
+{
+ ulong *loop, *def, *lab1;
+
+ mem(Oldw, 0, RCON, RA3); // n = t[0]
+ FM3I(2, Oadd, 4, RCON, RCON);
+ MOV(RA3, RA1);
+ FM3I(2, Osll, 1, RA1, RA1);
+ FM3(2, Oadd, RA3, RA1, RA1);
+ FM3I(2, Osll, 2, RA1, RA1);
+ FM3(3, Oldw, RCON, RA1, RLINK);
+
+ loop = code;
+ FM3(2, Ocmp, RZ, RA3, RZ);
+ def = code;
+ BRA(Oble, 0);
+ NOOP;
+
+ MOV(RA3, RA2); // MOVL DX, CX n2 = n
+ FM3I(2, Osra, 1, RA2, RA2); // SHR CX,1 n2 = n2>>1
+ MOV(RA2, RA1);
+ FM3I(2, Osll, 1, RA1, RA1);
+ FM3(2, Oadd, RA2, RA1, RA1);
+ FM3I(2, Osll, 2, RA1, RA1);
+
+ FM3(3, Oldw, RA1, RCON, RTA); // MOV (RA1+RCON), RTA
+ FM3(2, Ocmp, RTA, RA0, RZ);
+ lab1 = code;
+ BRA(Obge, 0);
+ NOOP;
+ MOV(RA2, RA3); // n = n2
+ BRA(Oba, loop-code);
+ NOOP;
+
+ PATCH(lab1);
+ FM3I(2, Oadd, 4, RA1, RTA);
+ FM3(3, Oldw, RTA, RCON, RTA); // MOV (RA1+RCON), RTA
+ FM3(2, Ocmp, RTA, RA0, RZ);
+ lab1 = code;
+ BRA(Obl, 0);
+ NOOP;
+
+ FM3I(2, Oadd, 12, RA1, RTA);
+ FM3(2, Oadd, RTA, RCON, RCON);
+ FM3(2, Osub, RA2, RA3, RA3); // SUBL CX, DX n -= n2
+ FM3I(2, Oadd, -1, RA3, RA3); // DECL DX n -= 1
+ BRA(Oba, loop-code);
+ NOOP;
+
+ PATCH(lab1);
+ FM3I(2, Oadd, 8, RA1, RTA);
+ FM3(3, Oldw, RTA, RCON, RLINK);
+
+ PATCH(def);
+ FM3I(2, Ojmpl, 0, RLINK, RZ);
+ NOOP;
+}
+
+static void
+macfrp(void)
+{
+ ulong *lab1, *lab2;
+
+ /* destroy the pointer in RA0 */
+ FM3I(2, Ocmp, -1, RA0, RZ);
+ lab1 = code;
+ BRA(Obe, 0);
+ NOOP;
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ FM3I(2, Oadd, -1, RA2, RA2);
+ FM3I(2, Ocmp, 0, RA2, RZ);
+ lab2 = code;
+ BRA(Obne, 0);
+ NOOP;
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ CALL(rdestroy);
+ mem(Ostw, O(REG, s), RREG, RA0);
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ RETURN;
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ PATCH(lab2);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ PATCH(lab1);
+ RETURN;
+ NOOP;
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ cp1 = code;
+ BRA(Obe, 0); // t(Rfp) == 0
+ NOOP;
+
+ mem(Oldw, O(Type,destroy),RA1, RA0);
+ FM3I(2, Ocmp, 0, RA0, RZ);
+ cp2 = code;
+ BRA(Obe, 0); // destroy(t(fp)) == 0
+ NOOP;
+
+ mem(Oldw, O(Frame,fp),RFP, RA2);
+ FM3I(2, Ocmp, 0, RA2, RZ);
+ cp3 = code;
+ BRA(Obe, 0); // fp(Rfp) == 0
+ NOOP;
+
+ mem(Oldw, O(Frame,mr),RFP, RA3);
+ FM3I(2, Ocmp, 0, RA3, RZ);
+ cp4 = code;
+ BRA(Obe, 0); // mr(Rfp) == 0
+ NOOP;
+
+ mem(Oldw, O(REG,M),RREG, RA2);
+ mem(Oldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+ FM3I(2, Oaddcc, -1, RA3, RA3);
+ cp5 = code;
+ BRA(Obe, 0); // --ref(arg) == 0
+ NOOP;
+ mem(Ostw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+ mem(Oldw, O(Frame,mr),RFP, RA1);
+ mem(Ostw, O(REG,M),RREG, RA1);
+ mem(Oldw, O(Modlink,compiled),RA1, RA2); // check for uncompiled code
+ mem(Oldw, O(Modlink,MP),RA1, RMP);
+ FM3I(2, Ocmp, 0, RA2, RZ);
+ cp6 = code;
+ BRA(Obe, 0);
+ NOOP;
+ mem(Ostw, O(REG,MP),RREG, RMP);
+
+ PATCH(cp4);
+ FM3I(2, Ojmpl, 0, RA0, RLINK); // call destroy(t(fp))
+ NOOP;
+ mem(Ostw, O(REG,SP),RREG, RFP);
+ mem(Oldw, O(Frame,lr),RFP, RA1);
+ mem(Oldw, O(Frame,fp),RFP, RFP);
+ mem(Ostw, O(REG,FP),RREG, RFP);
+ FM3I(2, Ojmpl, 0, RA1, RZ); // goto lr(Rfp)
+ NOOP;
+
+ PATCH(cp6);
+ FM3I(2, Ojmpl, 0, RA0, RLINK); // call destroy(t(fp))
+ NOOP;
+ mem(Ostw, O(REG,SP),RREG, RFP);
+ mem(Oldw, O(Frame,lr),RFP, RA1);
+ mem(Oldw, O(Frame,fp),RFP, RFP);
+ mem(Ostw, O(REG,FP),RREG, RFP);
+ mem(Oldw, O(REG,xpc),RREG, RA2);
+ FM3I(2, Oadd, 0x8, RA2, RA2);
+ FM3I(2, Ojmpl, 0, RA2, RZ); // return to uncompiled code
+ mem(Ostw, O(REG,PC),RREG, RA1);
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ ulong *br;
+
+ /* color the pointer in RA1 */
+ FM3I(2, Oadd, 1, RA0, RA0);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ mem(Oldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+ mem(Oldw, 0, RA2, RA2);
+ FM3(2, Ocmp, RA0, RA2, RZ);
+ br = code;
+ BRA(Obe, 0);
+ con(propagator, RA2, 1);
+ mem(Ostw, O(Heap, color)-sizeof(Heap), RA1, RA2);
+ con((ulong)&nprop, RA2, 1);
+ RETURN;
+ mem(Ostw, 0, RA2, RA2);
+ PATCH(br);
+ RETURN;
+ NOOP;
+}
+
+static void
+macmcal(void)
+{
+ ulong *lab1, *lab2;
+
+ mem(Oldw, O(Modlink, prog), RA3, RA1);
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ lab1 = code;
+ BRA(Obne, 0);
+ NOOP;
+
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, FP), RREG, RA2);
+ CALL(rmcall); // CALL rmcall
+ mem(Ostw, O(REG, dt), RREG, RA0);
+
+ con((ulong)&R, RREG, 1); // MOVL $R, RREG
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ NOOP;
+
+ PATCH(lab1); // patch:
+ FM3(2, Oor, RA2, RZ, RFP);
+ mem(Ostw, O(REG, M), RREG, RA3); // MOVL RA3, R.M
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ FM3I(2, Oadd, 1, RA1, RA1);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ mem(Oldw, O(Modlink, compiled), RA3, RA1);
+ mem(Oldw, O(Modlink, MP), RA3, RMP); // MOVL R.M->MP, RMP
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ lab2 = code;
+ BRA(Obe, 0);
+ mem(Ostw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->MP
+
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ NOOP;
+
+ PATCH(lab2);
+ mem(Ostw, O(REG,FP),RREG, RFP);
+ mem(Oldw, O(REG,xpc),RREG, RA1);
+ FM3I(2, Oadd, 0x8, RA1, RA1);
+ FM3I(2, Ojmpl, 0, RA1, RZ); // call to uncompiled code
+ mem(Ostw, O(REG,PC),RREG, RA0);
+}
+
+static void
+macfram(void)
+{
+ ulong *lab1;
+
+ mem(Oldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0
+ mem(Oldw, O(Type, size), RA3, RA1);
+ FM3(2, Oadd, RA0, RA1, RA0);
+ mem(Oldw, O(REG, TS), RREG, RA1);
+ FM3(2, Ocmp, RA1, RA0, RZ);
+ lab1 = code;
+ BRA(Obl, 0);
+ NOOP;
+
+ mem(Ostw, O(REG, s), RREG, RA3);
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ CALL(extend); // CALL extend
+ mem(Ostw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP); // MOVL R.MP, RMP
+ mem(Oldw, O(REG, s), RREG, RA2); // MOVL R.s, *R.d
+ mem(Oldw, O(REG, MP), RREG, RMP); // MOVL R.MP, RMP
+ RETURN; // RET
+ NOOP;
+
+ PATCH(lab1);
+ mem(Oldw, O(REG, SP), RREG, RA2); // MOVL R.SP, RA2
+ mem(Ostw, O(REG, SP), RREG, RA0); // MOVL RA0, R.SP
+
+ mem(Ostw, O(Frame, t), RA2, RA3); // MOVL RA3, t(RA2) f->t = t
+ mem(Oldw, O(Type, initialize), RA3, RA3);
+ FM3I(2, Ojmpl, 0, RA3, RZ);
+ mem(Ostw, REGMOD*4, RA2, RZ); // MOVL $0, mr(RA2) f->mr
+}
+
+static void
+macmfra(void)
+{
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, s), RREG, RA3); // Save type
+ mem(Ostw, O(REG, d), RREG, RA0); // Save destination
+ CALL(rmfram); // CALL rmfram
+ mem(Ostw, O(REG, FP), RREG, RFP);
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ NOOP;
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mem(Ostw, O(REG, dt), RREG, RLINK);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ CALL(base+macro[MacFRP]);
+ mem(Oldw, j, RFP, RA0);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ mem(Oldw, O(REG, dt), RREG, RLINK);
+ RETURN;
+ NOOP;
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RA0, 1);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Ostw, j, RA2, RA0);
+ j += sizeof(WORD*);
+ }
+ }
+ RETURN;
+ NOOP;
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 1)
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = mallocz(1024*sizeof(ulong), 0);
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ base = mallocz((n+nlit)*sizeof(*code), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 1)
+ print("dis=%5d %5d sparc=%5d asm=%.8p lit=%d: %s\n",
+ size, size*sizeof(Inst), n, base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 2) {
+ print("%d %D\n", i, &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ s = code;
+ mactab[i].gen();
+ if(cflag > 2) {
+ print("%s:\n", mactab[i].name);
+ das(s, code-s);
+ }
+ }
+
+ if(n != (code - base))
+ error(exCphase);
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(base);
+ return 0;
+}
diff --git a/libinterp/comp-spim.c b/libinterp/comp-spim.c
new file mode 100644
index 00000000..f8c34c33
--- /dev/null
+++ b/libinterp/comp-spim.c
@@ -0,0 +1 @@
+#include "comp-mips.c"
diff --git a/libinterp/comp-thumb.c b/libinterp/comp-thumb.c
new file mode 100644
index 00000000..03aaa20e
--- /dev/null
+++ b/libinterp/comp-thumb.c
@@ -0,0 +1,2466 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define RESCHED 1 /* check for interpreter reschedule */
+
+enum
+{
+ R0 = 0, // why wasn't this used ?
+ R1 = 1,
+ R2 = 2,
+ R3 = 3,
+ R4 = 4,
+ R5 = 5,
+ R6 = 6,
+ R7 = 7,
+ R8 = 8,
+ R9 = 9,
+ R10 = 10, // unused
+ R11 = 11, // unused
+ R12 = 12, /* C's SB */
+ R13 = 13, /* C's SP */
+ R14 = 14, /* Link Register */
+ R15 = 15, /* PC */
+
+ RSB = R12,
+ RLINK = R14,
+ RPC = R15,
+
+ RTMP = R11, /* linker temp */
+ RHT = R8, /* high temp */
+ RFP = R7, /* Frame Pointer */
+ RMP = R6, /* Module Pointer */
+ RREG = R5, /* Pointer to REG */
+ RA3 = R4, /* gpr 3 */
+ RA2 = R3, /* gpr 2 2+3 = L */
+ RA1 = R2, /* gpr 1 */
+ RA0 = R1, /* gpr 0 0+1 = L */
+ RCON = R0, /* Constant builder */
+
+ EQ = 0,
+ NE = 1,
+ CS = 2,
+ CC = 3,
+ MI = 4,
+ PL = 5,
+ VS = 6,
+ VC = 7,
+ HI = 8,
+ LS = 9,
+ GE = 10,
+ LT = 11,
+ GT = 12,
+ LE = 13,
+ AL = 14,
+ NV = 15,
+
+ And = 0,
+ Eor = 1,
+ Lsl = 2,
+ Lsr = 3,
+ Asr = 4,
+ Adc = 5,
+ Sbc = 6,
+ Ror = 7,
+ Tst = 8,
+ Neg = 9,
+ Cmp = 10,
+ Cmn = 11,
+ Orr = 12,
+ Mul = 13,
+ Bic = 14,
+ Mvn = 15,
+
+ Mov = 16,
+ Cmpi = 17,
+ Add = 18,
+ Sub = 19,
+
+ Cmph = 19,
+ Movh = 20,
+
+ Lea = 100, /* macro memory ops */
+ Ldw,
+ Ldb,
+ Stw,
+ Stb,
+
+ NCON = (0x3fc-8)/4,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET,
+ MacCASE,
+ MacCOLR,
+ MacMCAL,
+ MacFRAM,
+ MacMFRA,
+ MacRELQ,
+ NMACRO
+};
+
+#define FIRSTPASS 0
+#define MIDDLEPASS 1
+#define LASTPASS 2
+static int pass;
+
+static void
+OP(int o, int o1, int o2, char *s)
+{
+ if(o < o1 || o > o2) print("error: bad op %d in %s\n", o, s);
+}
+
+static void
+IMM(int i, int i1, int i2, char *s)
+{
+ if(i < i1 || i > i2) print("error: bad imm %d in %s\n", i, s);
+}
+
+static void
+MULT(int o, int m, char *s)
+{
+ if((o/m)*m != o) print("error: %d not multiple of %d in %s\n", o, m, s);
+}
+
+static void
+LOWREG(int r, char *s)
+{
+ if(r < 0 || r >= 8) print("error: %s: bad low reg %d\n", s, r);
+}
+
+static void
+HIGHREG(int r, char *s)
+{
+ if(r < 8) print("error: %s: bad high reg %d\n", s, r);
+}
+
+static void
+CKIRRS(int op, int i, int rm, int rd)
+{
+ OP(op, Lsl, Asr, "IRRS");
+ IMM(i, 0, 31, "IRRS");
+ LOWREG(rm, "IRRS rm");
+ LOWREG(rd, "IRRS rd");
+}
+
+static void
+CKRRR(int op, int rs, int rm, int rd)
+{
+ OP(op, Add, Sub, "RRR");
+ LOWREG(rs, "RRR rs");
+ LOWREG(rm, "RRR rm");
+ LOWREG(rd, "RRR rd");
+}
+
+static void
+CKIRR(int op, int i, int rm, int rd)
+{
+ OP(op, Add, Sub, "IRR");
+ IMM(i, 0, 7, "IRR");
+ LOWREG(rm, "IRR rm");
+ LOWREG(rd, "IRR rd");
+}
+
+static void
+CKIR(int op, int i, int rd)
+{
+ OP(op, Mov, Sub, "IR");
+ IMM(i, 0, 255, "IR");
+ LOWREG(rd, "IR rd");
+}
+
+static void
+CKRR(int op, int rs, int rd)
+{
+ OP(op, And, Mvn, "RR");
+ LOWREG(rs, "RR rs");
+ LOWREG(rd, "RR rd");
+}
+
+static void
+CKRH(int op, int rs, int rd)
+{
+ OP(op, Add, Movh, "RH");
+ LOWREG(rs, "RH");
+ HIGHREG(rd, "RH");
+}
+
+static void
+CKHR(int op, int rs, int rd)
+{
+ OP(op, Add, Movh, "HR");
+ HIGHREG(rs, "HR");
+ LOWREG(rd, "HR");
+}
+
+static void
+CKHH(int op, int rs, int rd)
+{
+ OP(op, Add, Movh, "HH");
+ HIGHREG(rs, "HH");
+ HIGHREG(rd, "HH");
+}
+
+static void
+CKLS(int rn, int o, int rd, int s, int l)
+{
+ char buf[16];
+
+ sprint(buf, "LS %d %d", s, l);
+ LOWREG(rn, buf);
+ LOWREG(rd, buf);
+ MULT(o, s, buf);
+ IMM(o/s, 0, 31, buf);
+}
+
+static void
+CKLSR(int rn, int rm, int rd, int s, int l)
+{
+ char buf[16];
+
+ sprint(buf, "LSR %d %d", s, l);
+ LOWREG(rn, buf);
+ LOWREG(rm, buf);
+ LOWREG(rd, buf);
+}
+
+static void
+CKLPCR(int o, int rd)
+{
+ LOWREG(rd, "LPCR");
+ if(o&3)
+ o += 2;
+ MULT(o, 4, "LPCR");
+ IMM(o/4, 0, 255, "LPCR");
+}
+
+static void
+CKB(int o)
+{
+ if(pass == FIRSTPASS)
+ return;
+ MULT(o, 2, "B");
+ IMM(o, -2048, 2046, "B");
+}
+
+static void
+CKBCC(int o)
+{
+ if(pass == FIRSTPASS)
+ return;
+ MULT(o, 2, "BCC");
+ IMM(o, -256, 254, "BCC");
+}
+
+static void
+CKBL(int o)
+{
+ if(pass == FIRSTPASS)
+ return;
+ MULT(o, 2, "BL");
+ IMM(o, -4194304, 4194302, "BL");
+}
+
+#define DPIRRS(op, i, rm, rd) (CKIRRS(op, i, rm, rd), *code++ = ((op-Lsl)<<11) | (i<<6) | (rm<<3) | rd)
+#define DPRRR(op, rs, rm, rd) (CKRRR(op, rs, rm, rd), *code++ = (6<<10) | ((op-Add)<<9) | (rs<<6) | (rm<<3) | rd)
+#define DPIRR(op, i, rm, rd) (CKIRR(op, i, rm, rd), *code++ = (7<<10) | ((op-Add)<<9) | (i<<6) | (rm<<3) | rd)
+#define DPIR(op, i, rd) (CKIR(op, i, rd), *code++ = (1<<13) | ((op-Mov)<<11) | (rd<<8) | i)
+#define DPRR(op, rs, rd) (CKRR(op, rs, rd), *code++ = (1<<14) | (op<<6) | (rs<<3) | rd)
+
+#define DPRH(op, rs, hd) (CKRH(op, rs, hd), *code++ = (17<<10) | ((op-Add)<<8) | (1<<7) | (rs<<3) | (hd-8))
+#define DPHR(op, hs, rd) (CKHR(op, hs, rd), *code++ = (17<<10) | ((op-Add)<<8) | (1<<6) | ((hs-8)<<3) | rd)
+#define DPHH(op, hs, hd) (CKHH(op, hs, hd), *code++ = (17<<10) | ((op-Add)<<8) | (3<<6) | ((hs-8)<<3) | (hd-8))
+
+#define LDW(rs, o, rd) (CKLS(rs, o, rd, 4, 1), *code++ = (13<<11)|((o/4)<<6)|(rs<<3)|rd)
+#define STW(rs, o, rd) (CKLS(rs, o, rd, 4, 0), *code++ = (12<<11)|((o/4)<<6)|(rs<<3)|rd)
+#define LDH(rs, o, rd) (CKLS(rs, o, rd, 2, 0), *code++ = (17<<11)|((o/2)<<6)|(rs<<3)|rd)
+#define STH(rs, o, rd) (CKLS(rs, o, rd, 2, 1), *code++ = (16<<11)|((o/2)<<6)|(rs<<3)|rd)
+#define LDB(rs, o, rd) (CKLS(rs, o, rd, 1, 1), *code++ = (15<<11)|(o<<6)|(rs<<3)|rd)
+#define STB(rs, o, rd) (CKLS(rs, o, rd, 1, 0), *code++ = (14<<11)|(o<<6)|(rs<<3)|rd)
+#define LDRW(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (44<<9)|(rs<<6)|(rm<<3)|rd)
+#define STRW(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (40<<9)|(rs<<6)|(rm<<3)|rd)
+#define LDRH(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (45<<9)|(rs<<6)|(rm<<3)|rd)
+#define STRH(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (41<<9)|(rs<<6)|(rm<<3)|rd)
+#define LDRB(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (46<<9)|(rs<<6)|(rm<<3)|rd)
+#define STRB(rs, rm, rd) (CKLSR(rs, rm, rd, 4, 1), *code++ = (42<<9)|(rs<<6)|(rm<<3)|rd)
+
+#define LDWPCREL(o, rd) (CKLPCR(o, rd), *code++ = (9<<11)|(rd<<8)|(o/4))
+
+#define CMPI(i, rn) DPIR(Cmpi, i, rn)
+#define CMP(rs, rn) DPRR(Cmp, rs, rn)
+#define CMPRH(rs, rn) DPRH(Cmph, rs, rn)
+#define CMPHR(rs, rn) DPHR(Cmph, rs, rn)
+#define CMPHH(rs, rn) DPHH(Cmph, rs, rn)
+#define MOV(src, dst) DPIRRS(Lsl, 0, src, dst)
+#define MOVRH(s, d) DPRH(Movh, s, d)
+#define MOVHR(s, d) DPHR(Movh, s, d)
+#define MOVHH(s, d) DPHH(Movh, s, d)
+#define MUL(rs, rd) DPRR(Mul, rs, rd)
+
+#define CODE (code+codeoff)
+#define IA(s, o) (ulong)(base+s[o])
+#define RELPC(pc) (ulong)(base+(pc))
+
+#define RINV(c) ((c)&1 ? (c)-1 : (c)+1)
+#define FPX(fp) (((ulong)(fp))&~1)
+#define NOBR 4
+
+#define BRAU(o) ((28<<11) | (((o)>>1)&0x7ff))
+#define BRAC(c, o) ((13<<12) | ((c)<<8) | (((o)>>1)&0xff))
+#define BRAL1(o) ((30<<11) | ((o)&0x7ff))
+#define BRAL2(o) ((31<<11) | ((o)&0x7ff))
+
+#define CJUMP(c, o) CBRA(RINV(c), o)
+#define BRA(o) (CKB((o)-4), gen(BRAU((o)-4)))
+#define CBRA(c, o) (CKBCC((o)-4), gen(BRAC(c, (o)-4)))
+#define BRADIS(o) branch(IA(patch, o)-(ulong)CODE)
+#define CBRADIS(c, o) cbranch(c, IA(patch, o)-(ulong)CODE)
+#define BRAMAC(o) branch(IA(macro, o)-(ulong)CODE)
+#define RETURN MOVHH(RLINK, RPC)
+#define CALL(o) call((ulong)(FPX(o))-(ulong)CODE)
+#define CALLMAC(o) call(IA(macro, o)-(ulong)CODE)
+
+#define PATCH(ptr) (CKB((ulong)code-(ulong)ptr-4), *ptr |= (((ulong)code-(ulong)(ptr)-4)>>1) & 0x7ff)
+#define CPATCH(ptr) (CKBCC((ulong)code-(ulong)ptr-4), *ptr |= (((ulong)code-(ulong)(ptr)-4)>>1) & 0xff)
+#define BPATCH(ptr) ((ulong)ptr-(ulong)code)
+
+/* long branches */
+#define DWORD(o) (*code++ = (o)&0xffff, *code++ = ((o)>>16)&0xffff)
+#define BRALONG(o) (LDWPCREL(0, RCON), MOVRH(RCON, RPC), DWORD(o+(ulong)code-4))
+#define CALLLONG(o) (MOVHR(RPC, RCON), DPIR(Add, 10, RCON), MOVRH(RCON, RLINK), BRALONG(o))
+
+#define PAD() MOVHH(RSB, RSB)
+
+#define BITS(B) (1<<B)
+
+#define FITS8(v) ((ulong)(v)<BITS(8))
+#define FITS5(v) ((ulong)(v)<BITS(5))
+#define FITS3(v) ((ulong)(v)<BITS(3))
+
+/* assumes H==-1 */
+#define CMPH(r, scr) DPIRR(Add, 1, r, scr)
+#define NOTNIL(r, scr) (CMPH(r, scr), label = code, CJUMP(EQ, NOBR), CALL(bounds), CPATCH(label))
+
+#define ADDSP(o) *code++ = (11<<12) | (0<<7) | (o>>2)
+#define SUBSP(o) *code++ = (11<<12) | (1<<7) | (o>>2)
+#define LDSP(o, r) *code++ = (19<<11) | (r<<8) | (o>>2)
+#define STSP(o, r) *code++ = (18<<11) | (r<<8) | (o>>2)
+
+static ushort* code;
+static ushort* base;
+static ulong* patch;
+static ulong codeoff;
+static Module* mod;
+static uchar* tinit;
+static ushort* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static void macrelq(void);
+static void movmem(Inst*);
+static void mid(Inst*, int, int);
+extern void das(ushort*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+ char* name;
+} mactab[] =
+{
+ MacFRP, macfrp, "FRP", /* decrement and free pointer */
+ MacRET, macret, "RET", /* return instruction */
+ MacCASE, maccase, "CASE", /* case instruction */
+ MacCOLR, maccolr, "COLR", /* increment and color pointer */
+ MacMCAL, macmcal, "MCAL", /* mcall bottom half */
+ MacFRAM, macfram, "FRAM", /* frame instruction */
+ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+typedef struct Const Const;
+struct Const
+{
+ ulong o;
+ ushort* code;
+ ushort* pc;
+};
+
+typedef struct Con Con;
+struct Con
+{
+ int ptr;
+ Const table[NCON];
+};
+static Con rcon;
+
+static void gen(ulong), genc(ulong);
+
+/* only CBRADIS could be too long by the look of things */
+static void
+cbranch(int c, long o)
+{
+ long off = o-4;
+
+ if(pass == FIRSTPASS || (off >= -256 && off <= 254))
+ CBRA(c, o);
+ else if(off >= -2046 && off <= 2048){
+ CBRA(RINV(c), 4);
+ BRA(o-2);
+ }
+ else{
+ if(!((int)CODE&2))
+ PAD();
+ CBRA(RINV(c), 10);
+ BRALONG(o);
+ }
+}
+
+/* only BRADIS, BRAMAC could be too long */
+static void
+branch(long o)
+{
+ long off = o-4;
+
+ if(pass == FIRSTPASS || (off >= -2048 && off <= 2046))
+ BRA(o);
+ else{
+ if((int)CODE&2)
+ PAD();
+ BRALONG(o);
+ }
+}
+
+static void
+call(long o)
+{
+ long off = o-4;
+
+ if(pass == FIRSTPASS || (off >= -4194304 && off <= 4194302))
+ genc(o);
+ else{
+ if(!((int)CODE&2))
+ PAD();
+ CALLLONG(o);
+ }
+}
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Frame *f;
+ Prog *p;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ if(R.d == H)
+ error(exModule);
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static void
+urk(char *s)
+{
+ USED(s);
+ error(exCompile); //production
+ //panic("compile failed: urk: %s\n", s); //debugging
+}
+
+static void
+gen(ulong w)
+{
+ *code++ = w;
+}
+
+static void
+genc(ulong o)
+{
+ o -= 4;
+ CKBL(o);
+ *code++ = BRAL1(o>>12);
+ *code++ = BRAL2(o>>1);
+}
+
+static void
+flushcon(int genbr)
+{
+ int i;
+ Const *c;
+ ulong disp;
+
+ if(rcon.ptr == 0)
+ return;
+ if(genbr ^ (((int)CODE&2)>>1))
+ PAD();
+ if(genbr)
+ BRA(rcon.ptr*4+2);
+ c = &rcon.table[0];
+ for(i = 0; i < rcon.ptr; i++) {
+ if(pass == LASTPASS){
+ disp = (code - c->code) * sizeof(*code) - 4;
+ if(disp >= BITS(10))
+ print("error: INVALID constant range %lud", disp);
+ CKLPCR(disp, R0); // any reg will do
+ if(disp & 3)
+ disp += 2; // ensure M(4) offset
+ *c->code |= (disp/4);
+ }
+ *code++ = (c->o)&0xffff;
+ *code++ = (c->o >> 16)&0xffff;
+ c++;
+ }
+ rcon.ptr = 0;
+}
+
+static void
+flushchk(void)
+{
+ if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(10)-256) // 256 allows for a little delay in calling flushchk
+ flushcon(1);
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+ Const *c;
+
+ LOWREG(r, "con");
+ if(opt != 0) {
+ if(o >= 0 && o <= 255){
+ DPIR(Mov, o, r);
+ return;
+ }
+ if(-o >= 0 && -o <= 255){
+ DPIR(Mov, -o, r);
+ DPRR(Neg, r, r);
+ return;
+ }
+ if(o >= 256 && o <= 510){
+ DPIR(Mov, 255, r);
+ DPIR(Add, o-255, r);
+ return;
+ }
+ if(o > 0){
+ int n = 0;
+ ulong m = o;
+
+ while(!(m & 1)){
+ n++;
+ m >>= 1;
+ }
+ if(m >= 0 && m <= 255){
+ DPIR(Mov, m, r);
+ DPIRRS(Lsl, n, r, r);
+ return;
+ }
+ }
+ }
+ flushchk();
+ c = &rcon.table[rcon.ptr++];
+ c->o = o;
+ c->code = code;
+ c->pc = code+codeoff;
+ LDWPCREL(0, r);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+ LOWREG(rm, "mem");
+ LOWREG(r, "mem");
+ LOWREG(RCON, "mem");
+ if(inst == Lea) {
+ if(rm == r){
+ if(disp < BITS(8)){
+ DPIR(Add, disp, r);
+ return;
+ }
+ if(-disp < BITS(8)){
+ DPIR(Sub, -disp, r);
+ return;
+ }
+ }
+ else{
+ if(disp < BITS(3)){
+ DPIRR(Add, disp, rm, r);
+ return;
+ }
+ if(-disp < BITS(3)){
+ DPIRR(Sub, -disp, rm, r);
+ return;
+ }
+ }
+ con(disp, RCON, 1);
+ DPRRR(Add, RCON, rm, r);
+ return;
+ }
+
+ switch(inst) {
+ case Ldw:
+ if(disp < BITS(7)){
+ LDW(rm, disp, r);
+ return;
+ }
+ break;
+ case Ldb:
+ if(disp < BITS(5)){
+ LDB(rm, disp, r);
+ return;
+ }
+ break;
+ case Stw:
+ if(disp < BITS(7)){
+ STW(rm, disp, r);
+ return;
+ }
+ break;
+ case Stb:
+ if(disp < BITS(5)){
+ STB(rm, disp, r);
+ return;
+ }
+ break;
+ }
+
+ con(disp, RCON, 1);
+ switch(inst) {
+ case Ldw:
+ LDRW(rm, RCON, r);
+ break;
+ case Ldb:
+ LDRB(rm, RCON, r);
+ break;
+ case Stw:
+ STRW(rm, RCON, r);
+ break;
+ case Stb:
+ STRB(rm, RCON, r);
+ break;
+ }
+}
+
+static void
+memh(int inst, ulong disp, int rm, int r)
+{
+ HIGHREG(r, "memh");
+ if(inst == Stw || inst == Stb)
+ MOVHR(r, RCON);
+ mem(inst, disp, rm, RCON);
+ if(inst != Stw && inst != Stb)
+ MOVRH(RCON, r);
+}
+
+static void
+opx(int mode, Adr *a, int mi, int r, int li)
+{
+ int ir, rta;
+
+ switch(mode) {
+ default:
+ urk("opx");
+ case AFP:
+ mem(mi, a->ind, RFP, r);
+ return;
+ case AMP:
+ mem(mi, a->ind, RMP, r);
+ return;
+ case AIMM:
+ con(a->imm, r, 1);
+ if(mi == Lea) { /* could be simpler if con generates reachable literal */
+ mem(Stw, li, RREG, r);
+ mem(Lea, li, RREG, r);
+ }
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ if(mi == Lea || mi == Ldb || mi == Ldw)
+ rta = r;
+ else if(r == RA3) /* seems safe - have to squeeze reg use */
+ rta = RA2;
+ else
+ rta = RA3;
+ mem(Ldw, a->i.f, ir, rta);
+ mem(mi, a->i.s, rta, r);
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+ opx(USRC(i->add), &i->s, op, reg, O(REG, st));
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+ opx(UDST(i->add), &i->d, op, reg, O(REG, dt));
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ con((ulong)litpool, RCON, 0);
+ mem(Stw, roff, RREG, RCON);
+
+ if(pass != LASTPASS)
+ return;
+
+ *litpool++ = imm&0xffff;
+ *litpool++ = (imm>>16)&0xffff;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ ushort *label;
+
+ if(RESCHED && i->d.ins <= i){
+ mem(Ldw, O(REG, IC), RREG, RA0);
+ DPIR(Sub, 1, RA0);
+ mem(Stw, O(REG, IC), RREG, RA0);
+ /* CMPI(1, RA0); */
+ label = code;
+ CBRA(LE, NOBR);
+ /* CJUMP(LE, NOBR); */
+ CALLMAC(MacRELQ);
+ CPATCH(label);
+ }
+}
+
+static void
+bounds(void)
+{
+ /* mem(Stw, O(REG,FP), RREG, RFP); */
+ error(exBounds);
+}
+
+/*
+static void
+called(int x)
+{
+ extern void ttrace(void);
+
+ if(x)
+ mem(Stw, O(REG, FP), RREG, RFP);
+ CALL(ttrace);
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+}
+*/
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+ ushort *label;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Lea, RA0);
+ mem(Stw, O(REG, s), RREG, RA0);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Lea, RA0);
+ mem(Stw, O(REG, d), RREG, RA0);
+ }
+ if(m & WRTPC) {
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Stw, O(REG, PC), RREG, RA0);
+ }
+ if(m & DBRAN) {
+ pc = patch[i->d.ins-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ mem(Ldw, O(REG, d), RREG, RA0);
+ mem(Stw, O(REG, m), RREG, RA0);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG,m));
+ break;
+ case AXINF:
+ mem(Lea, i->reg, RFP, RA2);
+ mem(Stw, O(REG, m), RREG, RA2);
+ break;
+ case AXINM:
+ mem(Lea, i->reg, RMP, RA2);
+ mem(Stw, O(REG, m), RREG, RA2);
+ break;
+ }
+ mem(Stw, O(REG, FP), RREG, RFP);
+
+ CALL(fn);
+
+ con((ulong)&R, RREG, 1);
+ if(m & TCHECK) {
+ mem(Ldw, O(REG, t), RREG, RA0);
+ CMPI(0, RA0);
+ label = code;
+ CJUMP(NE, NOBR);
+ memh(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; /* if(R.t) goto(R.xpc) */
+ CPATCH(label);
+ }
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+
+ if(m & NEWPC){
+ memh(Ldw, O(REG, PC), RREG, RPC);
+ flushcon(0);
+ }
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ if(mi == Lea)
+ urk("mid/lea");
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case GE:
+ return LE;
+ case LE:
+ return GE;
+ case GT:
+ return LT;
+ case LT:
+ return GT;
+ }
+ return b;
+}
+
+static void
+cbra(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) {
+ mid(i, Ldw, RA1);
+ CMPI(i->s.imm, RA1);
+ r = swapbraop(r);
+ } else if((i->add & ARM) == AXIMM && FITS8(i->reg)) {
+ opwld(i, Ldw, RA1);
+ CMPI(i->reg, RA1);
+ } else {
+ opwld(i, Ldw, RA0);
+ mid(i, Ldw, RA1);
+ CMP(RA1, RA0);
+ }
+ CBRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbrab(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ mid(i, Ldb, RA1);
+ CMPI(i->s.imm&0xff, RA1);
+ r = swapbraop(r);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Ldb, RA1);
+ CMPI(i->reg&0xff, RA1);
+ } else {
+ opwld(i, Ldb, RA0);
+ mid(i, Ldb, RA1);
+ CMP(RA1, RA0);
+ }
+ CBRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst;
+ ushort *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Lea, RA1);
+ mid(i, Lea, RA3);
+ mem(Ldw, 0, RA1, RA2);
+ mem(Ldw, 0, RA3, RA0);
+ CMP(RA0, RA2);
+ label = nil;
+ dst = i->d.ins-mod->prog;
+ switch(mode) {
+ case ANDAND:
+ label = code;
+ CBRA(jmsw, NOBR);
+ break;
+ case OROR:
+ CBRADIS(jmsw, dst);
+ break;
+ case EQAND:
+ CBRADIS(jmsw, dst);
+ label = code;
+ CBRA(NE, NOBR);
+ break;
+ }
+ mem(Ldw, 4, RA3, RA0);
+ mem(Ldw, 4, RA1, RA2);
+ CMP(RA0, RA2);
+ CBRADIS(jlsw, dst);
+ if(label != nil)
+ CPATCH(label);
+}
+
+static void
+cbraf(Inst *i, int r)
+{
+ USED(r);
+ if(RESCHED)
+ schedcheck(i);
+ punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Ldw, RA1); // v
+ opwst(i, Lea, RA3); // table
+ BRAMAC(MacCASE);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == FIRSTPASS || pass == MIDDLEPASS) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = RELPC(patch[t[2]]);
+ t += 3;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == FIRSTPASS || pass == MIDDLEPASS) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = RELPC(patch[t[4]]);
+ t += 6;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+ ushort *punt, *mlnil;
+
+ opwld(i, Ldw, RA0);
+ CMPH(RA0, RA3);
+ mlnil = code;
+ CBRA(EQ, NOBR);
+
+ if((i->add&ARM) == AXIMM) {
+ mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3);
+ } else {
+ mid(i, Ldw, RA1);
+ // RA1 = RA0 + (RA1<<3)
+ DPIRRS(Lsl, 3, RA1, RA1);
+ DPRRR(Add, RA0, RA1, RA1); // assumes sizeof(Modl) == 8
+ mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, RA3);
+ }
+
+ mem(Ldw, O(Type, initialize), RA3, RA1);
+ CMPI(0, RA1);
+ punt = code;
+ CBRA(NE, NOBR);
+
+ opwst(i, Lea, RA0);
+
+ /* Type in RA3, destination in RA0 */
+ CPATCH(mlnil);
+ con(RELPC(patch[i-mod->prog+1]), RA2, 0);
+ MOVRH(RA2, RLINK);
+ BRAMAC(MacMFRA);
+
+ /* Type in RA3 */
+ CPATCH(punt);
+ CALLMAC(MacFRAM);
+ opwst(i, Stw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+ ushort *mlnil;
+
+ opwld(i, Ldw, RA2);
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Stw, O(Frame, lr), RA2, RA0);
+ mem(Stw, O(Frame, fp), RA2, RFP);
+ mem(Ldw, O(REG, M), RREG, RA3);
+ mem(Stw, O(Frame, mr), RA2, RA3);
+ opwst(i, Ldw, RA3);
+ CMPH(RA3, RA0);
+ mlnil = code;
+ CBRA(EQ, NOBR);
+ if((i->add&ARM) == AXIMM) {
+ mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+ } else {
+ mid(i, Ldw, RA1);
+ DPIRRS(Lsl, 3, RA1, RA1);
+ DPRRR(Add, RA1, RA3, RA1); // assumes sizeof(Modl) == 8
+ mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0);
+ }
+ CPATCH(mlnil);
+ CALLMAC(MacMCAL);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Lea, RA0);
+ mid(i, Lea, RA3);
+ mem(Ldw, 4, RA0, RA1); // ls (big endian `big' even in little endian mode)
+ mem(Ldw, 4, RA3, RA2);
+ if(op == Add || op == Sub)
+ DPRRR(op, RA1, RA2, RA2);
+ else
+ DPRR(op, RA1, RA2); // ls: RA2 = RA2 op RA1
+ mem(Ldw, 0, RA0, RA1);
+ mem(Ldw, 0, RA3, RA0);
+ DPRR(opc, RA1, RA0); // ms: RA0 = RA0 opc RA1
+ if((i->add&ARM) != AXNON)
+ opwst(i, Lea, RA3);
+ mem(Stw, 0, RA3, RA0);
+ mem(Stw, 4, RA3, RA2);
+}
+
+static void
+movloop(Inst *i, int s)
+{
+ ushort *label;
+
+ opwst(i, Lea, RA2);
+ label = code;
+ if(s == 1)
+ LDB(RA1, 0, RA0);
+ else
+ LDW(RA1, 0, RA0);
+ DPIR(Add, s, RA1);
+ if(s == 1)
+ STB(RA2, 0, RA0);
+ else
+ STW(RA2, 0, RA0);
+ DPIR(Add, s, RA2);
+ DPIR(Sub, 1, RA3);
+ CBRA(NE, BPATCH(label));
+}
+
+static void
+movmem(Inst *i)
+{
+ ushort *cp;
+
+ // source address already in RA1
+ if((i->add&ARM) != AXIMM){
+ mid(i, Ldw, RA3);
+ CMPI(0, RA3);
+ cp = code;
+ CBRA(LE, NOBR);
+ movloop(i, 1);
+ CPATCH(cp);
+ return;
+ }
+ switch(i->reg){
+ case 0:
+ break;
+ case 4:
+ LDW(RA1, 0, RA2);
+ opwst(i, Stw, RA2);
+ break;
+ case 8:
+ LDW(RA1, 0, RA2);
+ opwst(i, Lea, RA3);
+ LDW(RA1, 4, RA1);
+ STW(RA3, 0, RA2);
+ STW(RA3, 4, RA1);
+ break;
+ default:
+ // could use ldm/stm loop...
+ if((i->reg&3) == 0) {
+ con(i->reg>>2, RA3, 1);
+ movloop(i, 4);
+ } else {
+ con(i->reg, RA3, 1);
+ movloop(i, 1);
+ }
+ break;
+ }
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ opwld(i, Ldw, RA1);
+ opwst(i, Lea, RA0);
+ DPIRRS(Lsl, 2, RA1, RA1);
+ LDRW(RA0, RA1, RA0);
+ MOVRH(RA0, RPC);
+ flushcon(0);
+
+ if(pass != LASTPASS)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = RELPC(patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comp(Inst *i)
+{
+ int r, imm;
+ char buf[64];
+ ushort *label, *label1;
+
+ flushchk();
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ // case ILSRW:
+ case ILSRL:
+ case IMODW:
+ case IMODB:
+ case IDIVW:
+ case IDIVB:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+/*
+ case IMODW:
+ case IMODB:
+ case IDIVW:
+ case IDIVB:
+ SUBSP(8);
+ mid(i, Ldw, RA0);
+ MOVRH(RA0, RTMP);
+ opwld(i, Ldw, RA0);
+ STSP(4, RA0); // movw RA0, 4(SP)
+ call // need to save, restore context
+ MOVHR(RTMP, RA0);
+ opwst(i, Stw, RA0);
+ ADDSP(8);
+*/
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ // case IHEADB:
+ // case IHEADW:
+ // case IHEADL:
+ // case IHEADF:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ //comcase(i, 0);
+ //punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break;
+ break;
+ case IGOTO:
+ comgoto(i);
+ //punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]); break;
+ break;
+ case IMOVL:
+ case IMOVF:
+ opwld(i, Lea, RA1);
+ LDW(RA1, 0, RA2);
+ LDW(RA1, 4, RA3);
+ opwst(i, Lea, RA1);
+ STW(RA1, 0, RA2);
+ STW(RA1, 4, RA3);
+ break;
+ case IHEADM:
+ //punt(i, SRCOP|DSTOP, optab[i->op]); break;
+ opwld(i, Ldw, RA1);
+ NOTNIL(RA1, RA2);
+ DPIR(Add, OA(List,data), RA1);
+ movmem(i);
+ break;
+ case IMOVM:
+ //punt(i, SRCOP|DSTOP, optab[i->op]); break;
+ opwld(i, Lea, RA1);
+ movmem(i);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RA3, 1);
+ CALL(base+macro[MacFRAM]);
+ opwst(i, Stw, RA2);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Ldb, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case ICVTWB:
+ opwld(i, Ldw, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case ILEA:
+ opwld(i, Lea, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IHEADW:
+ opwld(i, Ldw, RA0);
+ mem(Ldw, OA(List, data), RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IHEADB:
+ opwld(i, Ldw, RA0);
+ mem(Ldb, OA(List, data), RA0, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case IHEADL:
+ case IHEADF:
+ opwld(i, Ldw, RA0);
+ mem(Lea, OA(List, data), RA0, RA0);
+ LDW(RA0, 0, RA1);
+ LDW(RA0, 4, RA2);
+ opwst(i, Lea, RA0);
+ STW(RA0, 0, RA1);
+ STW(RA0, 4, RA2);
+ break;
+ case IMOVW:
+ opwld(i, Ldw, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMOVB:
+ opwld(i, Ldb, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case ITAIL:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0, RA1);
+ mem(Ldw, O(List, tail), RA0, RA1);
+ goto movp;
+ case IMOVP:
+ opwld(i, Ldw, RA1);
+ goto movp;
+ case IHEADP:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0, RA1);
+ mem(Ldw, OA(List, data), RA0, RA1);
+ movp:
+ CMPH(RA1, RA2);
+ label = code;
+ CJUMP(NE, NOBR);
+ CALLMAC(MacCOLR); // colour if not H
+ CPATCH(label);
+ opwst(i, Lea, RA2);
+ mem(Ldw, 0, RA2, RA0);
+ mem(Stw, 0, RA2, RA1);
+ CALLMAC(MacFRP);
+ break;
+ case ILENA:
+ opwld(i, Ldw, RA1);
+ con(0, RA0, 1);
+ CMPH(RA1, RA2);
+ CJUMP(NE, 4);
+ LDW(RA1, O(Array,len), RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case ILENC:
+ opwld(i, Ldw, RA1);
+ con(0, RA0, 1);
+ CMPH(RA1, RA2);
+ label = code;
+ CJUMP(NE, NOBR);
+ mem(Ldw, O(String,len),RA1, RA0);
+ CPATCH(label);
+ CMPI(0, RA0);
+ CJUMP(LT, 4);
+ DPRR(Neg, RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case ILENL:
+ con(0, RA0, 1);
+ opwld(i, Ldw, RA1);
+
+ label = code;
+ CMPH(RA1, RA2);
+ label1 = code;
+ CJUMP(NE, NOBR);
+ LDW(RA1, O(List, tail), RA1);
+ DPIR(Add, 1, RA0);
+ BRA(BPATCH(label));
+ CPATCH(label1);
+
+ opwst(i, Stw, RA0);
+ break;
+ case ICALL:
+ opwld(i, Ldw, RA0);
+ con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+ mem(Stw, O(Frame, lr), RA0, RA1);
+ mem(Stw, O(Frame, fp), RA0, RFP);
+ MOV(RA0, RFP);
+ BRADIS(i->d.ins-mod->prog);
+ flushcon(0);
+ break;
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ BRADIS(i->d.ins-mod->prog);
+ flushcon(0);
+ break;
+ case IBEQW:
+ cbra(i, EQ);
+ break;
+ case IBNEW:
+ cbra(i, NE);
+ break;
+ case IBLTW:
+ cbra(i, LT);
+ break;
+ case IBLEW:
+ cbra(i, LE);
+ break;
+ case IBGTW:
+ cbra(i, GT);
+ break;
+ case IBGEW:
+ cbra(i, GE);
+ break;
+ case IBEQB:
+ cbrab(i, EQ);
+ break;
+ case IBNEB:
+ cbrab(i, NE);
+ break;
+ case IBLTB:
+ cbrab(i, LT);
+ break;
+ case IBLEB:
+ cbrab(i, LE);
+ break;
+ case IBGTB:
+ cbrab(i, GT);
+ break;
+ case IBGEB:
+ cbrab(i, GE);
+ break;
+ case IBEQF:
+ cbraf(i, EQ);
+ break;
+ case IBNEF:
+ cbraf(i, NE);
+ break;
+ case IBLTF:
+ cbraf(i, LT);
+ break;
+ case IBLEF:
+ cbraf(i, LE);
+ break;
+ case IBGTF:
+ cbraf(i, GT);
+ break;
+ case IBGEF:
+ cbraf(i, GE);
+ break;
+ case IRET:
+ //punt(i, TCHECK|NEWPC, optab[i->op]); break;
+ mem(Ldw, O(Frame,t), RFP, RA1);
+ BRAMAC(MacRET);
+ break;
+ case IMULW:
+ opwld(i, Ldw, RA1);
+ mid(i, Ldw, RA0);
+ MUL(RA1, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMULB:
+ opwld(i, Ldb, RA1);
+ mid(i, Ldb, RA0);
+ MUL(RA1, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case IORW:
+ r = Orr;
+ goto arithw;
+ case IANDW:
+ r = And;
+ goto arithw;
+ case IXORW:
+ r = Eor;
+ goto arithw;
+ case ISUBW:
+ r = Sub;
+ goto arithw;
+ case IADDW:
+ r = Add;
+ arithw:
+ mid(i, Ldw, RA1);
+ if((r == Add || r == Sub) && UXSRC(i->add) == SRC(AIMM) && FITS3(i->s.imm)){
+ DPIRR(r, i->s.imm, RA1, RA0);
+ opwst(i, Stw, RA0);
+ }
+ else {
+ opwld(i, Ldw, RA0);
+ if(r == Add || r == Sub){
+ DPRRR(r, RA0, RA1, RA0);
+ opwst(i, Stw, RA0);
+ }
+ else{
+ DPRR(r, RA0, RA1);
+ opwst(i, Stw, RA1);
+ }
+ }
+ break;
+ case ISHRW:
+ r = Asr;
+ shiftw:
+ mid(i, Ldw, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm)){
+ DPIRRS(r, i->s.imm, RA1, RA0);
+ opwst(i, Stw, RA0);
+ }
+ else {
+ opwld(i, Ldw, RA0);
+ DPRR(r, RA0, RA1);
+ opwst(i, Stw, RA1);
+ }
+ break;
+ case ISHLW:
+ r = Lsl;
+ goto shiftw;
+ break;
+ case ILSRW:
+ r = Lsr;
+ goto shiftw;
+ break;
+ case IORB:
+ r = Orr;
+ goto arithb;
+ case IANDB:
+ r = And;
+ goto arithb;
+ case IXORB:
+ r = Eor;
+ goto arithb;
+ case ISUBB:
+ r = Sub;
+ goto arithb;
+ case IADDB:
+ r = Add;
+ arithb:
+ mid(i, Ldb, RA1);
+ if((r == Add || r == Sub) && UXSRC(i->add) == SRC(AIMM) && FITS3(i->s.imm)){
+ DPIRR(r, i->s.imm, RA1, RA0);
+ opwst(i, Stb, RA0);
+ }
+ else {
+ opwld(i, Ldb, RA0);
+ if(r == Add || r == Sub){
+ DPRRR(r, RA0, RA1, RA0);
+ opwst(i, Stb, RA0);
+ }
+ else{
+ DPRR(r, RA0, RA1);
+ opwst(i, Stb, RA1);
+ }
+ }
+ break;
+ case ISHRB:
+ r = Asr;
+ goto shiftb;
+ case ISHLB:
+ r = Lsl;
+ shiftb:
+ mid(i, Ldb, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm)){
+ DPIRRS(r, i->s.imm, RA1, RA0);
+ opwst(i, Stb, RA0);
+ }
+ else {
+ opwld(i, Ldw, RA0);
+ DPRR(r, RA0, RA1);
+ opwst(i, Stb, RA1);
+ }
+ break;
+ case IINDC:
+ opwld(i, Ldw, RA1); // RA1 = string
+ NOTNIL(RA1, RA2);
+ imm = 1;
+ if((i->add&ARM) != AXIMM || !FITS8((short)i->reg<<1)){
+ mid(i, Ldw, RA2); // RA2 = i
+ imm = 0;
+ }
+ mem(Ldw, O(String,len),RA1, RA0); // len<0 => index Runes, otherwise bytes
+ // BUG: check !((ulong)i >= abs(a->len))
+ DPIR(Add, O(String,data), RA1);
+ CMPI(0, RA0);
+ if(imm){
+ label = code;
+ CJUMP(GE, NOBR);
+ if(i->reg < BITS(5))
+ LDB(RA1, i->reg, RA3);
+ else{
+ con(i->reg, RCON, 1);
+ LDRB(RA1, RCON, RA3);
+ }
+ CPATCH(label);
+ label = code;
+ CJUMP(LT, NOBR);
+ if((ushort)((short)i->reg<<1) < BITS(6))
+ LDH(RA1, (short)i->reg<<1, RA3);
+ else{
+ con((short)i->reg<<1, RCON, 1);
+ LDRH(RA1, RCON, RA3);
+ }
+ CPATCH(label);
+ } else {
+ CJUMP(GE, 4);
+ LDRB(RA1, RA2, RA3);
+ CJUMP(LT, 6);
+ DPIRRS(Lsl, 1, RA2, RA2);
+ LDRH(RA1, RA2, RA3);
+ }
+ opwst(i, Stw, RA3);
+ break;
+ case IINDL:
+ case IINDF:
+ case IINDW:
+ case IINDB:
+ opwld(i, Ldw, RA0); /* a */
+ NOTNIL(RA0, RA1);
+ mem(Ldw, O(Array, data), RA0, RA0);
+ r = 0;
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ r = 3;
+ break;
+ case IINDW:
+ r = 2;
+ break;
+ }
+ if(UXDST(i->add) == DST(AIMM) && FITS8(i->d.imm<<r)) {
+ DPIR(Add, (i->d.imm<<r), RA0);
+ } else {
+ opwst(i, Ldw, RA1);
+ DPIRRS(Lsl, r, RA1, RA1);
+ DPRRR(Add, RA0, RA1, RA0);
+ }
+ mid(i, Stw, RA0);
+ break;
+ case IINDX:
+ opwld(i, Ldw, RA0); /* a */
+ NOTNIL(RA0, RA1);
+ opwst(i, Ldw, RA1); /* i */
+
+ mem(Ldw, O(Array, t), RA0, RA2);
+ mem(Ldw, O(Array, data), RA0, RA0);
+ mem(Ldw, O(Type, size), RA2, RA2);
+ MUL(RA2, RA1);
+ DPRRR(Add, RA0, RA1, RA0);
+ mid(i, Stw, RA0);
+ break;
+ case IADDL:
+ larith(i, Add, Adc);
+ break;
+ case ISUBL:
+ larith(i, Sub, Sbc);
+ break;
+ case IORL:
+ larith(i, Orr, Orr);
+ break;
+ case IANDL:
+ larith(i, And, And);
+ break;
+ case IXORL:
+ larith(i, Eor, Eor);
+ break;
+ case ICVTWL:
+ opwld(i, Ldw, RA1);
+ opwst(i, Lea, RA2);
+ DPIRRS(Asr, 16, RA1, RA0);
+ DPIRRS(Asr, 16, RA0, RA0);
+ STW(RA2, 0, RA0);
+ STW(RA2, 4, RA1);
+ break;
+ case ICVTLW:
+ opwld(i, Lea, RA0);
+ mem(Ldw, 4, RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IBEQL:
+ cbral(i, NE, EQ, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, NE, NE, OROR);
+ break;
+ case IBLEL:
+ cbral(i, LT, LS, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, GT, HI, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, LT, CC, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, GT, CS, EQAND);
+ break;
+ case ICVTFL:
+ case ICVTLF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ // case IMOVF:
+ // punt(i, SRCOP|DSTOP, optab[i->op]);
+ // break;
+ case IDIVF:
+ goto arithf;
+ case IMULF:
+ goto arithf;
+ case ISUBF:
+ goto arithf;
+ case IADDF:
+ arithf:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEGF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICVTWF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICVTFW:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ISHLL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISHRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(10 * sizeof(*code));
+ if(comvec == nil)
+ error(exNomem);
+ code = (ushort*)comvec;
+
+ con((ulong)&R, RREG, 0);
+ memh(Stw, O(REG, xpc), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ memh(Ldw, O(REG, PC), RREG, RPC);
+ pass = LASTPASS;
+ flushcon(0);
+ pass = FIRSTPASS;
+ // print("preamble\n");
+ // das((ushort*)comvec, code-(ushort*)comvec);
+ segflush(comvec, 10 * sizeof(*code));
+ comvec =(void *)((ulong)comvec | 1); /* T bit */
+}
+
+static void
+maccase(void)
+{
+ ushort *cp1, *loop, *inner, *label;
+/*
+ * RA1, RHT = value (input arg), t
+ * RA2 = count, n
+ * RA3 = table pointer (input arg)
+ * RA0 = n/2, n2
+ * RCON = pivot element t+n/2*3, l
+ */
+ MOVRH(RA1, RHT);
+ LDW(RA3, 0, RA2); // count from table
+ MOVRH(RA3, RLINK); // initial table pointer
+
+ loop = code; // loop:
+ CMPI(0, RA2);
+ cp1 = code;
+ CBRA(LE, NOBR); // n <= 0? goto out
+
+ inner = code;
+ DPIRRS(Lsr, 1, RA2, RA0);
+ DPIRRS(Lsl, 1, RA0, RCON);
+ DPRRR(Add, RA0, RCON, RCON);
+ DPIRRS(Lsl, 2, RCON, RCON);
+ DPRRR(Add, RA3, RCON, RCON);
+
+ LDW(RCON, 4, RA1);
+ CMPRH(RA1, RHT);
+ label = code;
+ CJUMP(LT, NOBR);
+ MOV(RA0, RA2);
+ BRA(BPATCH(loop)); // v < l[1]? goto loop
+ CPATCH(label);
+
+ LDW(RCON, 8, RA1);
+ CMPRH(RA1, RHT);
+ CJUMP(LT, 6);
+ LDW(RCON, 12, RA1);
+ MOVRH(RA1, RPC); // v >= l[1] && v < l[2] => found; goto l[3]
+
+ // v >= l[2] (high)
+ DPIRR(Add, 7, RCON, RA3);
+ DPIR(Add, 5, RA3);
+ DPIRR(Add, 1, RA0, RA1);
+ DPRRR(Sub, RA1, RA2, RA2);
+ CBRA(GT, BPATCH(inner)); // n > 0? goto loop
+
+ CPATCH(cp1); // out:
+ MOVHR(RLINK, RA2);
+ LDW(RA2, 0, RA2); // initial n
+ DPIRRS(Lsl, 1, RA2, RA0);
+ DPRRR(Add, RA2, RA0, RA2);
+ DPIRRS(Lsl, 2, RA2, RA2);
+ DPRH(Add, RA2, RLINK);
+ MOVHR(RLINK, RA2);
+ LDW(RA2, 4, RA1);
+ MOVRH(RA1, RPC); // goto (initial t)[n*3+1]
+}
+
+static void
+macfrp(void)
+{
+ ushort *label;
+
+ /* destroy the pointer in RA0 */
+ CMPH(RA0, RA2);
+ CJUMP(EQ, 4);
+ RETURN; // arg == H? => return
+
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ DPIR(Sub, 1, RA2);
+ label = code;
+ CJUMP(NE, NOBR);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ RETURN; // --h->ref != 0 => return
+ CPATCH(label);
+
+ mem(Stw, O(REG, FP), RREG, RFP);
+ memh(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, s), RREG, RA0);
+ CALL(rdestroy);
+ con((ulong)&R, RREG, 1);
+ memh(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ flushcon(0);
+}
+
+static void
+maccolr(void)
+{
+ /* color the pointer in RA1 */
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ DPIR(Add, 1, RA0);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0); // h->ref++
+ con((ulong)&mutator, RA2, 1);
+ mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+ mem(Ldw, 0, RA2, RA2);
+ CMP(RA2, RA0);
+ CJUMP(EQ, 4);
+ RETURN; // return if h->color == mutator
+ con(propagator, RA2, 1);
+ mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2); // h->color = propagator
+ con((ulong)&nprop, RA2, 1);
+ mem(Stw, 0, RA2, RA2); // nprop = !0
+ RETURN;
+ flushcon(0);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ ushort *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+
+ CMPI(0, RA1);
+ cp1 = code;
+ CBRA(EQ, NOBR); // t(Rfp) == 0
+
+ mem(Ldw, O(Type,destroy),RA1, RA0);
+ CMPI(0, RA0);
+ cp2 = code;
+ CBRA(EQ, NOBR); // destroy(t(fp)) == 0
+
+ mem(Ldw, O(Frame,fp),RFP, RA2);
+ CMPI(0, RA2);
+ cp3 = code;
+ CBRA(EQ, NOBR); // fp(Rfp) == 0
+
+ mem(Ldw, O(Frame,mr),RFP, RA3);
+ CMPI(0, RA3);
+ cp4 = code;
+ CBRA(EQ, NOBR); // mr(Rfp) == 0
+
+ mem(Ldw, O(REG,M),RREG, RA2);
+ mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+ DPIR(Sub, 1, RA3);
+ cp5 = code;
+ CBRA(EQ, NOBR); // --ref(arg) == 0
+ mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+ mem(Ldw, O(Frame,mr),RFP, RA1);
+ mem(Stw, O(REG,M),RREG, RA1);
+ mem(Ldw, O(Modlink,MP),RA1, RMP);
+ mem(Stw, O(REG,MP),RREG, RMP);
+ mem(Ldw, O(Modlink,compiled), RA1, RA3); // R.M->compiled
+ CMPI(0, RA3);
+ linterp = code;
+ CBRA(EQ, NOBR);
+
+ CPATCH(cp4);
+ MOVHH(RPC, RLINK); // call destroy(t(fp))
+ MOVRH(RA0, RPC);
+
+ mem(Stw, O(REG,SP),RREG, RFP);
+ mem(Ldw, O(Frame,lr),RFP, RA1);
+ mem(Ldw, O(Frame,fp),RFP, RFP);
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ MOVRH(RA1, RPC);
+
+ CPATCH(linterp);
+ MOVHH(RPC, RLINK); // call destroy(t(fp))
+ MOVRH(RA0, RPC);
+
+ mem(Stw, O(REG,SP),RREG, RFP);
+ mem(Ldw, O(Frame,lr),RFP, RA1);
+ mem(Ldw, O(Frame,fp),RFP, RFP);
+ mem(Stw, O(REG,PC),RREG, RA1); // R.PC = fp->lr
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ memh(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; // return to xec uncompiled code
+
+ CPATCH(cp1);
+ CPATCH(cp2);
+ CPATCH(cp3);
+ CPATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macmcal(void)
+{
+ ushort *lab, *label;
+
+ CMPH(RA0, RA1);
+ label = code;
+ CJUMP(NE, NOBR);
+ mem(Ldw, O(Modlink, prog), RA3, RA1); // RA0 != H
+ CMPI(0, RA1); // RA0 != H
+ lab = code;
+ CBRA(NE, NOBR); // RA0 != H && m->prog!=0
+ CPATCH(label);
+
+ memh(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, FP), RREG, RA2);
+ mem(Stw, O(REG, dt), RREG, RA0);
+ CALL(rmcall); // CALL rmcall
+
+ con((ulong)&R, RREG, 1); // MOVL $R, RREG
+ memh(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+
+ CPATCH(lab); // patch:
+ MOV(RA2, RFP);
+ mem(Stw, O(REG, M), RREG, RA3); // MOVL RA3, R.M
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ DPIR(Add, 1, RA1);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ mem(Ldw, O(Modlink, MP), RA3, RMP); // MOVL R.M->mp, RMP
+ mem(Stw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->m
+ mem(Ldw, O(Modlink,compiled), RA3, RA1); // M.compiled?
+ CMPI(0, RA1);
+ CJUMP(NE, 4);
+ MOVRH(RA0, RPC);
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Stw, O(REG,PC),RREG, RA0); // R.PC = RPC
+ memh(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; // return to xec uncompiled code
+ flushcon(0);
+}
+
+static void
+macfram(void)
+{
+ ushort *lab1;
+
+ mem(Ldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0
+ mem(Ldw, O(Type, size), RA3, RA1);
+ DPRRR(Add, RA0, RA1, RA0);
+ mem(Ldw, O(REG, TS), RREG, RA1);
+ CMP(RA1, RA0); // nsp :: R.TS
+ lab1 = code;
+ CBRA(CS, NOBR); // nsp >= R.TS; must expand
+
+ mem(Ldw, O(REG, SP), RREG, RA2); // MOVL R.SP, RA2
+ mem(Stw, O(REG, SP), RREG, RA0); // MOVL RA0, R.SP
+
+ mem(Stw, O(Frame, t), RA2, RA3); // MOVL RA3, t(RA2) f->t = t
+ con(0, RA0, 1);
+ mem(Stw, O(Frame,mr), RA2, RA0); // MOVL $0, mr(RA2) f->mr
+ memh(Ldw, O(Type, initialize), RA3, RPC); // become t->init(RA2), returning RA2
+
+ CPATCH(lab1);
+ mem(Stw, O(REG, s), RREG, RA3);
+ memh(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP
+ CALL(extend); // CALL extend
+
+ con((ulong)&R, RREG, 1);
+ memh(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP); // MOVL R.FP, RFP
+ mem(Ldw, O(REG, s), RREG, RA2); // MOVL R.s, *R.d
+ mem(Ldw, O(REG, MP), RREG, RMP); // MOVL R.MP, RMP
+ RETURN; // RET
+}
+
+static void
+macmfra(void)
+{
+ memh(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, s), RREG, RA3); // Save type
+ mem(Stw, O(REG, d), RREG, RA0); // Save destination
+ mem(Stw, O(REG, FP), RREG, RFP);
+ CALL(rmfram); // CALL rmfram
+
+ con((ulong)&R, RREG, 1);
+ memh(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+}
+
+static void
+macrelq(void)
+{
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ memh(Stw, O(REG,PC),RREG, RLINK); // R.PC = RLINK
+ memh(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN;
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ memh(Stw, O(REG, dt), RREG, RLINK);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ mem(Ldw, j, RFP, RA0);
+ CALL(base+macro[MacFRP]);
+ }
+ j += sizeof(WORD*);
+ }
+ flushchk();
+ }
+ memh(Ldw, O(REG, dt), RREG, RLINK);
+ RETURN;
+ flushcon(0);
+}
+
+void
+comi(Type *t)
+{
+ int i, j = 0, m, c, r;
+
+ if(t->np > 4){
+ r = RA3;
+ MOV(RA2, RA3);
+ }
+ else
+ r = RA2;
+ con((ulong)H, RA0, 1);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ if(j == 128){
+ if(t->np <= 4) print("error: bad j in comi\n");
+ DPIR(Add, 128, RA3);
+ j = 0;
+ }
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Stw, j, r, RA0);
+ j += sizeof(WORD*);
+ }
+ flushchk();
+ }
+ RETURN;
+ flushcon(0);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ushort *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+// print("type\n");
+// das(start, code-start);
+
+ if(cflag > 1)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ushort *s, *tmp;
+ int again, lastc = 0, lastn = 0;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = malloc(4096*sizeof(ulong));
+ base = tmp;
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ pass = FIRSTPASS;
+
+ do{
+ again = 0;
+ n = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ codeoff = n;
+ code = tmp;
+ comp(&m->prog[i]);
+ if(patch[i] != n)
+ again = 1;
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ codeoff = n;
+ code = tmp;
+ mactab[i].gen();
+ if(macro[mactab[i].idx] != n)
+ again = 1;
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+ code = tmp;
+ flushcon(0);
+ n += code - tmp;
+ if(code-tmp != lastc || n != lastn)
+ again = 1;
+ lastc = code-tmp;
+ lastn = n;
+
+ if(pass == FIRSTPASS)
+ pass = MIDDLEPASS;
+
+ }while(again);
+
+ base = mallocz((n+nlit)*sizeof(*code), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 1)
+ print("dis=%5d %5d 386=%5d asm=%.8lux: %s\n",
+ size, size*sizeof(Inst), n, base, m->name);
+
+ pass = LASTPASS;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+ n = 0;
+ codeoff = 0;
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ print("error: %lud != %d\n", patch[i], n);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 2) {
+ print("%3d %D\n", i, &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ s = code;
+ mactab[i].gen();
+ if(macro[mactab[i].idx] != n){
+ print("error: mac phase err: %lud != %d\n", macro[mactab[i].idx], n);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 2) {
+ print("%s:\n", mactab[i].name);
+ das(s, code-s);
+ }
+ }
+ s = code;
+ flushcon(0);
+ n += code - s;
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+// print("comvec at %lux\n", (ulong)comvec);
+// print("base at %lux-%lux\n", (ulong)base, (ulong)base+2*n);
+// print("entry %lux prog %lux\n", (ulong)m->entry, (ulong)m->prog);
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(base);
+ free(tmp);
+ return 0;
+}
diff --git a/libinterp/conv.c b/libinterp/conv.c
new file mode 100644
index 00000000..b5a8e94c
--- /dev/null
+++ b/libinterp/conv.c
@@ -0,0 +1,110 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "mathi.h"
+
+enum
+{
+ TOKI0,
+ TOKI1,
+ TOKI2,
+ TOKI3,
+ TOKSB,
+ TOKFP
+};
+#include "tab.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ uchar mode;
+ Adr a;
+};
+
+#pragma varargck type "a" Addr*
+
+char* opnam[256];
+int iconv(Fmt*);
+int aconv(Fmt*);
+
+int
+aconv(Fmt *f)
+{
+ Addr *a;
+ char buf[64];
+
+ a = va_arg(f->args, Addr*);
+ if(a == nil)
+ return fmtstrcpy(f, "AZ");
+ switch(a->mode & AMASK) {
+ case AFP: sprint(buf, "%d(fp)", a->a.ind); break;
+ case AMP: sprint(buf, "%d(mp)", a->a.ind); break;
+ case AIMM: sprint(buf, "$%d", a->a.imm); break;
+ case AIND|AFP: sprint(buf, "%d(%d(fp))", a->a.i.s, a->a.i.f); break;
+ case AIND|AMP: sprint(buf, "%d(%d(mp))", a->a.i.s, a->a.i.f); break;
+ }
+ return fmtstrcpy(f, buf);
+}
+
+int
+Dconv(Fmt *f)
+{
+ int j;
+ Inst *i;
+ Addr s, d;
+ char buf[128];
+ static int init;
+
+ if(init == 0) {
+ for(j = 0; keywds[j].name != nil; j++)
+ opnam[keywds[j].op] = keywds[j].name;
+
+ fmtinstall('a', aconv);
+ init = 1;
+ }
+
+ i = va_arg(f->args, Inst*);
+ if(i == nil)
+ return fmtstrcpy(f, "IZ");
+
+ switch(keywds[i->op].terminal) {
+ case TOKI0:
+ sprint(buf, "%s", opnam[i->op]);
+ break;
+ case TOKI1:
+ d.a = i->d;
+ d.mode = UDST(i->add);
+ sprint(buf, "%s\t%a", opnam[i->op], &d);
+ break;
+ case TOKI3:
+ d.a = i->d;
+ d.mode = UDST(i->add);
+ s.a = i->s;
+ s.mode = USRC(i->add);
+ switch(i->add&ARM) {
+ default:
+ sprint(buf, "%s\t%a, %a", opnam[i->op], &s, &d);
+ break;
+ case AXIMM:
+ sprint(buf, "%s\t%a, $%d, %a", opnam[i->op], &s, i->reg, &d);
+ break;
+ case AXINF:
+ sprint(buf, "%s\t%a, %d(fp), %a", opnam[i->op], &s, i->reg, &d);
+ break;
+ case AXINM:
+ sprint(buf, "%s\t%a, %d(mp), %a", opnam[i->op], &s, i->reg, &d);
+ break;
+ }
+ break;
+ case TOKI2:
+ d.a = i->d;
+ d.mode = UDST(i->add);
+ s.a = i->s;
+ s.mode = USRC(i->add);
+ sprint(buf, "%s\t%a, %a", opnam[i->op], &s, &d);
+ break;
+ }
+
+ return fmtstrcpy(f, buf);
+}
+
diff --git a/libinterp/das-386.c b/libinterp/das-386.c
new file mode 100644
index 00000000..bc34c1a8
--- /dev/null
+++ b/libinterp/das-386.c
@@ -0,0 +1,1630 @@
+#include <lib9.h>
+#include <kernel.h>
+
+int i386inst(ulong, char, char*, int);
+int i386das(ulong, char*, int);
+int i386instlen(ulong);
+
+static uchar *dasdata;
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+/*
+ * an instruction
+ */
+typedef struct Instr Instr;
+struct Instr
+{
+ uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
+ ulong addr; /* address of start of instruction */
+ int n; /* number of bytes in instruction */
+ char *prefix; /* instr prefix */
+ char *segment; /* segment override */
+ uchar jumptype; /* set to the operand type for jump/ret/call */
+ char osize; /* 'W' or 'L' */
+ char asize; /* address size 'W' or 'L' */
+ uchar mod; /* bits 6-7 of mod r/m field */
+ uchar reg; /* bits 3-5 of mod r/m field */
+ char ss; /* bits 6-7 of SIB */
+ char index; /* bits 3-5 of SIB */
+ char base; /* bits 0-2 of SIB */
+ short seg; /* segment of far address */
+ ulong disp; /* displacement */
+ ulong imm; /* immediate */
+ ulong imm2; /* second immediate operand */
+ char *curr; /* fill level in output buffer */
+ char *end; /* end of output buffer */
+ char *err; /* error message */
+};
+
+ /* 386 register (ha!) set */
+enum{
+ AX=0,
+ CX,
+ DX,
+ BX,
+ SP,
+ BP,
+ SI,
+ DI,
+};
+ /* Operand Format codes */
+/*
+%A - address size register modifier (!asize -> 'E')
+%C - Control register CR0/CR1/CR2
+%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I - second immediate operand
+%O - Operand size register modifier (!osize -> 'E')
+%T - Test register TR6/TR7
+%S - size code ('W' or 'L')
+%X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d - displacement 16-32 bits
+%e - effective address - Mod R/M value
+%f - floating point register F0-F7 - from Mod R/M register
+%g - segment register
+%i - immediate operand 8-32 bits
+%p - PC-relative - signed displacement in immediate field
+%r - Reg from Mod R/M
+%x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+ char operand[2];
+ void *proto; /* actually either (char*) or (Optable*) */
+};
+ /* Operand decoding codes */
+enum {
+ Ib = 1, /* 8-bit immediate - (no sign extension)*/
+ Ibs, /* 8-bit immediate (sign extended) */
+ Jbs, /* 8-bit sign-extended immediate in jump or call */
+ Iw, /* 16-bit immediate -> imm */
+ Iw2, /* 16-bit immediate -> imm2 */
+ Iwd, /* Operand-sized immediate (no sign extension)*/
+ Awd, /* Address offset */
+ Iwds, /* Operand-sized immediate (sign extended) */
+ RM, /* Word or long R/M field with register (/r) */
+ RMB, /* Byte R/M field with register (/r) */
+ RMOP, /* Word or long R/M field with op code (/digit) */
+ RMOPB, /* Byte R/M field with op code (/digit) */
+ RMR, /* R/M register only (mod = 11) */
+ RMM, /* R/M memory only (mod = 0/1/2) */
+ R0, /* Base reg of Mod R/M is literal 0x00 */
+ R1, /* Base reg of Mod R/M is literal 0x01 */
+ FRMOP, /* Floating point R/M field with opcode */
+ FRMEX, /* Extended floating point R/M field with opcode */
+ JUMP, /* Jump or Call flag - no operand */
+ RET, /* Return flag - no operand */
+ OA, /* literal 0x0a byte */
+ PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ AUX, /* Multi-byte op code - Auxiliary table */
+ PRE, /* Instr Prefix */
+ SEG, /* Segment Prefix */
+ OPOVER, /* Operand size override */
+ ADDOVER, /* Address size override */
+};
+
+static Optable optab0F00[8]=
+{
+ 0,0, "MOVW LDT,%e",
+ 0,0, "MOVW TR,%e",
+ 0,0, "MOVW %e,LDT",
+ 0,0, "MOVW %e,TR",
+ 0,0, "VERR %e",
+ 0,0, "VERW %e",
+};
+
+static Optable optab0F01[8]=
+{
+ 0,0, "MOVL GDTR,%e",
+ 0,0, "MOVL IDTR,%e",
+ 0,0, "MOVL %e,GDTR",
+ 0,0, "MOVL %e,IDTR",
+ 0,0, "MOVW MSW,%e", /* word */
+ 0,0, nil,
+ 0,0, "MOVW %e,MSW", /* word */
+};
+
+static Optable optab0FBA[8]=
+{
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ Ib,0, "BT%S %i,%e",
+ Ib,0, "BTS%S %i,%e",
+ Ib,0, "BTR%S %i,%e",
+ Ib,0, "BTC%S %i,%e",
+};
+
+static Optable optab0F[256]=
+{
+ RMOP,0, optab0F00,
+ RMOP,0, optab0F01,
+ RM,0, "LAR %e,%r",
+ RM,0, "LSL %e,%r",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "CLTS",
+ 0,0, nil,
+ 0,0, "INVD",
+ 0,0, "WBINVD",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ RMR,0, "MOVL %C,%e", /* [0x20] */
+ RMR,0, "MOVL %D,%e",
+ RMR,0, "MOVL %e,%C",
+ RMR,0, "MOVL %e,%D",
+ RMR,0, "MOVL %T,%e",
+ 0,0, nil,
+ RMR,0, "MOVL %e,%T",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, "WRMSR", /* [0x30] */
+ 0,0, "RDTSC",
+ 0,0, "RDMSR",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ Iwds,0, "JOS %p", /* [0x80] */
+ Iwds,0, "JOC %p",
+ Iwds,0, "JCS %p",
+ Iwds,0, "JCC %p",
+ Iwds,0, "JEQ %p",
+ Iwds,0, "JNE %p",
+ Iwds,0, "JLS %p",
+ Iwds,0, "JHI %p",
+ Iwds,0, "JMI %p",
+ Iwds,0, "JPL %p",
+ Iwds,0, "JPS %p",
+ Iwds,0, "JPC %p",
+ Iwds,0, "JLT %p",
+ Iwds,0, "JGE %p",
+ Iwds,0, "JLE %p",
+ Iwds,0, "JGT %p",
+
+ RMB,0, "SETOS %e", /* [0x90] */
+ RMB,0, "SETOC %e",
+ RMB,0, "SETCS %e",
+ RMB,0, "SETCC %e",
+ RMB,0, "SETEQ %e",
+ RMB,0, "SETNE %e",
+ RMB,0, "SETLS %e",
+ RMB,0, "SETHI %e",
+ RMB,0, "SETMI %e",
+ RMB,0, "SETPL %e",
+ RMB,0, "SETPS %e",
+ RMB,0, "SETPC %e",
+ RMB,0, "SETLT %e",
+ RMB,0, "SETGE %e",
+ RMB,0, "SETLE %e",
+ RMB,0, "SETGT %e",
+
+ 0,0, "PUSHL FS", /* [0xa0] */
+ 0,0, "POPL FS",
+ 0,0, "CPUID",
+ RM,0, "BT%S %r,%e",
+ RM,Ib, "SHLD%S %r,%i,%e",
+ RM,0, "SHLD%S %r,CL,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "PUSHL GS",
+ 0,0, "POPL GS",
+ 0,0, nil,
+ RM,0, "BTS%S %r,%e",
+ RM,Ib, "SHRD%S %r,%i,%e",
+ RM,0, "SHRD%S %r,CL,%e",
+ 0,0, nil,
+ RM,0, "IMUL%S %e,%r",
+
+ 0,0, nil,
+ 0,0, nil,
+ RMM,0, "LSS %e,%r", /* [0xb2] */
+ RM,0, "BTR%S %r,%e",
+ RMM,0, "LFS %e,%r",
+ RMM,0, "LGS %e,%r",
+ RMB,0, "MOVBZX %e,%R",
+ RM,0, "MOVWZX %e,%R",
+ 0,0, nil,
+ 0,0, nil,
+ RMOP,0, optab0FBA,
+ RM,0, "BTC%S %e,%r",
+ RM,0, "BSF%S %e,%r",
+ RM,0, "BSR%S %e,%r",
+ RMB,0, "MOVBSX %e,%R",
+ RM,0, "MOVWSX %e,%R",
+};
+
+static Optable optab80[8]=
+{
+ Ib,0, "ADDB %i,%e",
+ Ib,0, "ORB %i,%e",
+ Ib,0, "ADCB %i,%e",
+ Ib,0, "SBBB %i,%e",
+ Ib,0, "ANDB %i,%e",
+ Ib,0, "SUBB %i,%e",
+ Ib,0, "XORB %i,%e",
+ Ib,0, "CMPB %e,%i",
+};
+
+static Optable optab81[8]=
+{
+ Iwd,0, "ADD%S %i,%e",
+ Iwd,0, "OR%S %i,%e",
+ Iwd,0, "ADC%S %i,%e",
+ Iwd,0, "SBB%S %i,%e",
+ Iwd,0, "AND%S %i,%e",
+ Iwd,0, "SUB%S %i,%e",
+ Iwd,0, "XOR%S %i,%e",
+ Iwd,0, "CMP%S %e,%i",
+};
+
+static Optable optab83[8]=
+{
+ Ibs,0, "ADD%S %i,%e",
+ Ibs,0, "OR%S %i,%e",
+ Ibs,0, "ADC%S %i,%e",
+ Ibs,0, "SBB%S %i,%e",
+ Ibs,0, "AND%S %i,%e",
+ Ibs,0, "SUB%S %i,%e",
+ Ibs,0, "XOR%S %i,%e",
+ Ibs,0, "CMP%S %e,%i",
+};
+
+static Optable optabC0[8] =
+{
+ Ib,0, "ROLB %i,%e",
+ Ib,0, "RORB %i,%e",
+ Ib,0, "RCLB %i,%e",
+ Ib,0, "RCRB %i,%e",
+ Ib,0, "SHLB %i,%e",
+ Ib,0, "SHRB %i,%e",
+ 0,0, nil,
+ Ib,0, "SARB %i,%e",
+};
+
+static Optable optabC1[8] =
+{
+ Ib,0, "ROL%S %i,%e",
+ Ib,0, "ROR%S %i,%e",
+ Ib,0, "RCL%S %i,%e",
+ Ib,0, "RCR%S %i,%e",
+ Ib,0, "SHL%S %i,%e",
+ Ib,0, "SHR%S %i,%e",
+ 0,0, nil,
+ Ib,0, "SAR%S %i,%e",
+};
+
+static Optable optabD0[8] =
+{
+ 0,0, "ROLB %e",
+ 0,0, "RORB %e",
+ 0,0, "RCLB %e",
+ 0,0, "RCRB %e",
+ 0,0, "SHLB %e",
+ 0,0, "SHRB %e",
+ 0,0, nil,
+ 0,0, "SARB %e",
+};
+
+static Optable optabD1[8] =
+{
+ 0,0, "ROL%S %e",
+ 0,0, "ROR%S %e",
+ 0,0, "RCL%S %e",
+ 0,0, "RCR%S %e",
+ 0,0, "SHL%S %e",
+ 0,0, "SHR%S %e",
+ 0,0, nil,
+ 0,0, "SAR%S %e",
+};
+
+static Optable optabD2[8] =
+{
+ 0,0, "ROLB CL,%e",
+ 0,0, "RORB CL,%e",
+ 0,0, "RCLB CL,%e",
+ 0,0, "RCRB CL,%e",
+ 0,0, "SHLB CL,%e",
+ 0,0, "SHRB CL,%e",
+ 0,0, nil,
+ 0,0, "SARB CL,%e",
+};
+
+static Optable optabD3[8] =
+{
+ 0,0, "ROL%S CL,%e",
+ 0,0, "ROR%S CL,%e",
+ 0,0, "RCL%S CL,%e",
+ 0,0, "RCR%S CL,%e",
+ 0,0, "SHL%S CL,%e",
+ 0,0, "SHR%S CL,%e",
+ 0,0, nil,
+ 0,0, "SAR%S CL,%e",
+};
+
+static Optable optabD8[8+8] =
+{
+ 0,0, "FADDF %e,F0",
+ 0,0, "FMULF %e,F0",
+ 0,0, "FCOMF %e,F0",
+ 0,0, "FCOMFP %e,F0",
+ 0,0, "FSUBF %e,F0",
+ 0,0, "FSUBRF %e,F0",
+ 0,0, "FDIVF %e,F0",
+ 0,0, "FDIVRF %e,F0",
+ 0,0, "FADDD %f,F0",
+ 0,0, "FMULD %f,F0",
+ 0,0, "FCOMD %f,F0",
+ 0,0, "FCOMPD %f,F0",
+ 0,0, "FSUBD %f,F0",
+ 0,0, "FSUBRD %f,F0",
+ 0,0, "FDIVD %f,F0",
+ 0,0, "FDIVRD %f,F0",
+};
+/*
+ * optabD9 and optabDB use the following encoding:
+ * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ * else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ * the instructions for MOD == 3, follow the 8 instructions
+ * for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+ 0,0, "FMOVF %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVF F0,%e",
+ 0,0, "FMOVFP F0,%e",
+ 0,0, "FLDENV%S %e",
+ 0,0, "FLDCW %e",
+ 0,0, "FSTENV%S %e",
+ 0,0, "FSTCW %e",
+ 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
+ 0,0, "FMOVD F1,F0",
+ 0,0, "FMOVD F2,F0",
+ 0,0, "FMOVD F3,F0",
+ 0,0, "FMOVD F4,F0",
+ 0,0, "FMOVD F5,F0",
+ 0,0, "FMOVD F6,F0",
+ 0,0, "FMOVD F7,F0",
+ 0,0, "FXCHD F0,F0",
+ 0,0, "FXCHD F1,F0",
+ 0,0, "FXCHD F2,F0",
+ 0,0, "FXCHD F3,F0",
+ 0,0, "FXCHD F4,F0",
+ 0,0, "FXCHD F5,F0",
+ 0,0, "FXCHD F6,F0",
+ 0,0, "FXCHD F7,F0",
+ 0,0, "FNOP",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FCHS", /* [0x28] */
+ 0,0, "FABS",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FTST",
+ 0,0, "FXAM",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FLD1",
+ 0,0, "FLDL2T",
+ 0,0, "FLDL2E",
+ 0,0, "FLDPI",
+ 0,0, "FLDLG2",
+ 0,0, "FLDLN2",
+ 0,0, "FLDZ",
+ 0,0, nil,
+ 0,0, "F2XM1",
+ 0,0, "FYL2X",
+ 0,0, "FPTAN",
+ 0,0, "FPATAN",
+ 0,0, "FXTRACT",
+ 0,0, "FPREM1",
+ 0,0, "FDECSTP",
+ 0,0, "FNCSTP",
+ 0,0, "FPREM",
+ 0,0, "FYL2XP1",
+ 0,0, "FSQRT",
+ 0,0, "FSINCOS",
+ 0,0, "FRNDINT",
+ 0,0, "FSCALE",
+ 0,0, "FSIN",
+ 0,0, "FCOS",
+};
+
+static Optable optabDA[8+8] =
+{
+ 0,0, "FADDL %e,F0",
+ 0,0, "FMULL %e,F0",
+ 0,0, "FCOML %e,F0",
+ 0,0, "FCOMLP %e,F0",
+ 0,0, "FSUBL %e,F0",
+ 0,0, "FSUBRL %e,F0",
+ 0,0, "FDIVL %e,F0",
+ 0,0, "FDIVRL %e,F0",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ R1,0, "FUCOMPP", /* [0x0d] */
+};
+
+static Optable optabDB[8+64] =
+{
+ 0,0, "FMOVL %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVL F0,%e",
+ 0,0, "FMOVLP F0,%e",
+ 0,0, nil,
+ 0,0, "FMOVX %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVXP F0,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FCLEX", /* [0x2a] */
+ 0,0, "FINIT",
+};
+
+static Optable optabDC[8+8] =
+{
+ 0,0, "FADDD %e,F0",
+ 0,0, "FMULD %e,F0",
+ 0,0, "FCOMD %e,F0",
+ 0,0, "FCOMDP %e,F0",
+ 0,0, "FSUBD %e,F0",
+ 0,0, "FSUBRD %e,F0",
+ 0,0, "FDIVD %e,F0",
+ 0,0, "FDIVRD %e,F0",
+ 0,0, "FADDD F0,%f",
+ 0,0, "FMULD F0,%f",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FSUBRD F0,%f",
+ 0,0, "FSUBD F0,%f",
+ 0,0, "FDIVRD F0,%f",
+ 0,0, "FDIVD F0,%f",
+};
+
+static Optable optabDD[8+8] =
+{
+ 0,0, "FMOVD %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVD F0,%e",
+ 0,0, "FMOVDP F0,%e",
+ 0,0, "FRSTOR%S %e",
+ 0,0, nil,
+ 0,0, "FSAVE%S %e",
+ 0,0, "FSTSW %e",
+ 0,0, "FFREED %f",
+ 0,0, nil,
+ 0,0, "FMOVD %f,F0",
+ 0,0, "FMOVDP %f,F0",
+ 0,0, "FUCOMD %f,F0",
+ 0,0, "FUCOMDP %f,F0",
+};
+
+static Optable optabDE[8+8] =
+{
+ 0,0, "FADDW %e,F0",
+ 0,0, "FMULW %e,F0",
+ 0,0, "FCOMW %e,F0",
+ 0,0, "FCOMWP %e,F0",
+ 0,0, "FSUBW %e,F0",
+ 0,0, "FSUBRW %e,F0",
+ 0,0, "FDIVW %e,F0",
+ 0,0, "FDIVRW %e,F0",
+ 0,0, "FADDDP F0,%f",
+ 0,0, "FMULDP F0,%f",
+ 0,0, nil,
+ R1,0, "FCOMPDP",
+ 0,0, "FSUBRDP F0,%f",
+ 0,0, "FSUBDP F0,%f",
+ 0,0, "FDIVRDP F0,%f",
+ 0,0, "FDIVDP F0,%f",
+};
+
+static Optable optabDF[8+8] =
+{
+ 0,0, "FMOVW %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVW F0,%e",
+ 0,0, "FMOVWP F0,%e",
+ 0,0, "FBLD %e",
+ 0,0, "FMOVL %e,F0",
+ 0,0, "FBSTP %e",
+ 0,0, "FMOVLP F0,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ R0,0, "FSTSW %OAX",
+};
+
+static Optable optabF6[8] =
+{
+ Ib,0, "TESTB %i,%e",
+ 0,0, nil,
+ 0,0, "NOTB %e",
+ 0,0, "NEGB %e",
+ 0,0, "MULB AL,%e",
+ 0,0, "IMULB AL,%e",
+ 0,0, "DIVB AL,%e",
+ 0,0, "IDIVB AL,%e",
+};
+
+static Optable optabF7[8] =
+{
+ Iwd,0, "TEST%S %i,%e",
+ 0,0, nil,
+ 0,0, "NOT%S %e",
+ 0,0, "NEG%S %e",
+ 0,0, "MUL%S %OAX,%e",
+ 0,0, "IMUL%S %OAX,%e",
+ 0,0, "DIV%S %OAX,%e",
+ 0,0, "IDIV%S %OAX,%e",
+};
+
+static Optable optabFE[8] =
+{
+ 0,0, "INCB %e",
+ 0,0, "DECB %e",
+};
+
+static Optable optabFF[8] =
+{
+ 0,0, "INC%S %e",
+ 0,0, "DEC%S %e",
+ JUMP,0, "CALL*%S %e",
+ JUMP,0, "CALLF*%S %e",
+ JUMP,0, "JMP*%S %e",
+ JUMP,0, "JMPF*%S %e",
+ 0,0, "PUSHL %e",
+};
+
+static Optable optable[256] =
+{
+ RMB,0, "ADDB %r,%e",
+ RM,0, "ADD%S %r,%e",
+ RMB,0, "ADDB %e,%r",
+ RM,0, "ADD%S %e,%r",
+ Ib,0, "ADDB %i,AL",
+ Iwd,0, "ADD%S %i,%OAX",
+ 0,0, "PUSHL ES",
+ 0,0, "POPL ES",
+ RMB,0, "ORB %r,%e",
+ RM,0, "OR%S %r,%e",
+ RMB,0, "ORB %e,%r",
+ RM,0, "OR%S %e,%r",
+ Ib,0, "ORB %i,AL",
+ Iwd,0, "OR%S %i,%OAX",
+ 0,0, "PUSHL CS",
+ AUX,0, optab0F,
+ RMB,0, "ADCB %r,%e",
+ RM,0, "ADC%S %r,%e",
+ RMB,0, "ADCB %e,%r",
+ RM,0, "ADC%S %e,%r",
+ Ib,0, "ADCB %i,AL",
+ Iwd,0, "ADC%S %i,%OAX",
+ 0,0, "PUSHL SS",
+ 0,0, "POPL SS",
+ RMB,0, "SBBB %r,%e",
+ RM,0, "SBB%S %r,%e",
+ RMB,0, "SBBB %e,%r",
+ RM,0, "SBB%S %e,%r",
+ Ib,0, "SBBB %i,AL",
+ Iwd,0, "SBB%S %i,%OAX",
+ 0,0, "PUSHL DS",
+ 0,0, "POPL DS",
+ RMB,0, "ANDB %r,%e",
+ RM,0, "AND%S %r,%e",
+ RMB,0, "ANDB %e,%r",
+ RM,0, "AND%S %e,%r",
+ Ib,0, "ANDB %i,AL",
+ Iwd,0, "AND%S %i,%OAX",
+ SEG,0, "ES:",
+ 0,0, "DAA",
+ RMB,0, "SUBB %r,%e",
+ RM,0, "SUB%S %r,%e",
+ RMB,0, "SUBB %e,%r",
+ RM,0, "SUB%S %e,%r",
+ Ib,0, "SUBB %i,AL",
+ Iwd,0, "SUB%S %i,%OAX",
+ SEG,0, "CS:",
+ 0,0, "DAS",
+ RMB,0, "XORB %r,%e",
+ RM,0, "XOR%S %r,%e",
+ RMB,0, "XORB %e,%r",
+ RM,0, "XOR%S %e,%r",
+ Ib,0, "XORB %i,AL",
+ Iwd,0, "XOR%S %i,%OAX",
+ SEG,0, "SS:",
+ 0,0, "AAA",
+ RMB,0, "CMPB %r,%e",
+ RM,0, "CMP%S %r,%e",
+ RMB,0, "CMPB %e,%r",
+ RM,0, "CMP%S %e,%r",
+ Ib,0, "CMPB %i,AL",
+ Iwd,0, "CMP%S %i,%OAX",
+ SEG,0, "DS:",
+ 0,0, "AAS",
+ 0,0, "INC%S %OAX",
+ 0,0, "INC%S %OCX",
+ 0,0, "INC%S %ODX",
+ 0,0, "INC%S %OBX",
+ 0,0, "INC%S %OSP",
+ 0,0, "INC%S %OBP",
+ 0,0, "INC%S %OSI",
+ 0,0, "INC%S %ODI",
+ 0,0, "DEC%S %OAX",
+ 0,0, "DEC%S %OCX",
+ 0,0, "DEC%S %ODX",
+ 0,0, "DEC%S %OBX",
+ 0,0, "DEC%S %OSP",
+ 0,0, "DEC%S %OBP",
+ 0,0, "DEC%S %OSI",
+ 0,0, "DEC%S %ODI",
+ 0,0, "PUSH%S %OAX",
+ 0,0, "PUSH%S %OCX",
+ 0,0, "PUSH%S %ODX",
+ 0,0, "PUSH%S %OBX",
+ 0,0, "PUSH%S %OSP",
+ 0,0, "PUSH%S %OBP",
+ 0,0, "PUSH%S %OSI",
+ 0,0, "PUSH%S %ODI",
+ 0,0, "POP%S %OAX",
+ 0,0, "POP%S %OCX",
+ 0,0, "POP%S %ODX",
+ 0,0, "POP%S %OBX",
+ 0,0, "POP%S %OSP",
+ 0,0, "POP%S %OBP",
+ 0,0, "POP%S %OSI",
+ 0,0, "POP%S %ODI",
+ 0,0, "PUSHA%S",
+ 0,0, "POPA%S",
+ RMM,0, "BOUND %e,%r",
+ RM,0, "ARPL %r,%e",
+ SEG,0, "FS:",
+ SEG,0, "GS:",
+ OPOVER,0, "",
+ ADDOVER,0, "",
+ Iwd,0, "PUSH%S %i",
+ RM,Iwd, "IMUL%S %e,%i,%r",
+ Ib,0, "PUSH%S %i",
+ RM,Ibs, "IMUL%S %e,%i,%r",
+ 0,0, "INSB DX,(%ODI)",
+ 0,0, "INS%S DX,(%ODI)",
+ 0,0, "OUTSB (%ASI),DX",
+ 0,0, "OUTS%S (%ASI),DX",
+ Jbs,0, "JOS %p",
+ Jbs,0, "JOC %p",
+ Jbs,0, "JCS %p",
+ Jbs,0, "JCC %p",
+ Jbs,0, "JEQ %p",
+ Jbs,0, "JNE %p",
+ Jbs,0, "JLS %p",
+ Jbs,0, "JHI %p",
+ Jbs,0, "JMI %p",
+ Jbs,0, "JPL %p",
+ Jbs,0, "JPS %p",
+ Jbs,0, "JPC %p",
+ Jbs,0, "JLT %p",
+ Jbs,0, "JGE %p",
+ Jbs,0, "JLE %p",
+ Jbs,0, "JGT %p",
+ RMOPB,0, optab80,
+ RMOP,0, optab81,
+ 0,0, nil,
+ RMOP,0, optab83,
+ RMB,0, "TESTB %r,%e",
+ RM,0, "TEST%S %r,%e",
+ RMB,0, "XCHGB %r,%e",
+ RM,0, "XCHG%S %r,%e",
+ RMB,0, "MOVB %r,%e",
+ RM,0, "MOV%S %r,%e",
+ RMB,0, "MOVB %e,%r",
+ RM,0, "MOV%S %e,%r",
+ RM,0, "MOVW %g,%e",
+ RM,0, "LEA %e,%r",
+ RM,0, "MOVW %e,%g",
+ RM,0, "POP%S %e",
+ 0,0, "NOP",
+ 0,0, "XCHG %OCX,%OAX",
+ 0,0, "XCHG %ODX,%OAX",
+ 0,0, "XCHG %OBX,%OAX",
+ 0,0, "XCHG %OSP,%OAX",
+ 0,0, "XCHG %OBP,%OAX",
+ 0,0, "XCHG %OSI,%OAX",
+ 0,0, "XCHG %ODI,%OAX",
+ 0,0, "%X", /* miserable CBW or CWDE */
+ 0,0, "%x", /* idiotic CWD or CDQ */
+ PTR,0, "CALL%S %d",
+ 0,0, "WAIT",
+ 0,0, "PUSH FLAGS",
+ 0,0, "POP FLAGS",
+ 0,0, "SAHF",
+ 0,0, "LAHF",
+ Awd,0, "MOVB %i,AL",
+ Awd,0, "MOV%S %i,%OAX",
+ Awd,0, "MOVB AL,%i",
+ Awd,0, "MOV%S %OAX,%i",
+ 0,0, "MOVSB (%ASI),(%ADI)",
+ 0,0, "MOVS%S (%ASI),(%ADI)",
+ 0,0, "CMPSB (%ASI),(%ADI)",
+ 0,0, "CMPS%S (%ASI),(%ADI)",
+ Ib,0, "TESTB %i,AL",
+ Iwd,0, "TEST%S %i,%OAX",
+ 0,0, "STOSB AL,(%ADI)",
+ 0,0, "STOS%S %OAX,(%ADI)",
+ 0,0, "LODSB (%ASI),AL",
+ 0,0, "LODS%S (%ASI),%OAX",
+ 0,0, "SCASB (%ADI),AL",
+ 0,0, "SCAS%S (%ADI),%OAX",
+ Ib,0, "MOVB %i,AL",
+ Ib,0, "MOVB %i,CL",
+ Ib,0, "MOVB %i,DL",
+ Ib,0, "MOVB %i,BL",
+ Ib,0, "MOVB %i,AH",
+ Ib,0, "MOVB %i,CH",
+ Ib,0, "MOVB %i,DH",
+ Ib,0, "MOVB %i,BH",
+ Iwd,0, "MOV%S %i,%OAX",
+ Iwd,0, "MOV%S %i,%OCX",
+ Iwd,0, "MOV%S %i,%ODX",
+ Iwd,0, "MOV%S %i,%OBX",
+ Iwd,0, "MOV%S %i,%OSP",
+ Iwd,0, "MOV%S %i,%OBP",
+ Iwd,0, "MOV%S %i,%OSI",
+ Iwd,0, "MOV%S %i,%ODI",
+ RMOPB,0, optabC0,
+ RMOP,0, optabC1,
+ Iw,0, "RET %i",
+ RET,0, "RET",
+ RM,0, "LES %e,%r",
+ RM,0, "LDS %e,%r",
+ RMB,Ib, "MOVB %i,%e",
+ RM,Iwd, "MOV%S %i,%e",
+ Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
+ RET,0, "LEAVE", /* bizarre LEAVE */
+ Iw,0, "RETF %i",
+ RET,0, "RETF",
+ 0,0, "INT 3",
+ Ib,0, "INTB %i",
+ 0,0, "INTO",
+ 0,0, "IRET",
+ RMOPB,0, optabD0,
+ RMOP,0, optabD1,
+ RMOPB,0, optabD2,
+ RMOP,0, optabD3,
+ OA,0, "AAM",
+ OA,0, "AAD",
+ 0,0, nil,
+ 0,0, "XLAT",
+ FRMOP,0, optabD8,
+ FRMEX,0, optabD9,
+ FRMOP,0, optabDA,
+ FRMEX,0, optabDB,
+ FRMOP,0, optabDC,
+ FRMOP,0, optabDD,
+ FRMOP,0, optabDE,
+ FRMOP,0, optabDF,
+ Jbs,0, "LOOPNE %p",
+ Jbs,0, "LOOPE %p",
+ Jbs,0, "LOOP %p",
+ Jbs,0, "JCXZ %p",
+ Ib,0, "INB %i,AL",
+ Ib,0, "IN%S %i,%OAX",
+ Ib,0, "OUTB AL,%i",
+ Ib,0, "OUT%S %OAX,%i",
+ Iwds,0, "CALL %p",
+ Iwds,0, "JMP %p",
+ PTR,0, "JMP %d",
+ Jbs,0, "JMP %p",
+ 0,0, "INB DX,AL",
+ 0,0, "IN%S DX,%OAX",
+ 0,0, "OUTB AL,DX",
+ 0,0, "OUT%S %OAX,DX",
+ PRE,0, "LOCK",
+ 0,0, nil,
+ PRE,0, "REPNE",
+ PRE,0, "REP",
+ 0,0, "HALT",
+ 0,0, "CMC",
+ RMOPB,0, optabF6,
+ RMOP,0, optabF7,
+ 0,0, "CLC",
+ 0,0, "STC",
+ 0,0, "CLI",
+ 0,0, "STI",
+ 0,0, "CLD",
+ 0,0, "STD",
+ RMOPB,0, optabFE,
+ RMOP,0, optabFF,
+};
+
+/*
+ * get a byte of the instruction
+ */
+static int
+igetc(Instr *ip, uchar *c)
+{
+ if(ip->n+1 > sizeof(ip->mem)){
+ kwerrstr("instruction too long");
+ return -1;
+ }
+ *c = dasdata[ip->addr+ip->n];
+ ip->mem[ip->n++] = *c;
+ return 1;
+}
+
+/*
+ * get two bytes of the instruction
+ */
+static int
+igets(Instr *ip, ushort *sp)
+{
+ uchar c;
+ ushort s;
+
+ if (igetc(ip, &c) < 0)
+ return -1;
+ s = c;
+ if (igetc(ip, &c) < 0)
+ return -1;
+ s |= (c<<8);
+ *sp = s;
+ return 1;
+}
+
+/*
+ * get 4 bytes of the instruction
+ */
+static int
+igetl(Instr *ip, ulong *lp)
+{
+ ushort s;
+ long l;
+
+ if (igets(ip, &s) < 0)
+ return -1;
+ l = s;
+ if (igets(ip, &s) < 0)
+ return -1;
+ l |= (s<<16);
+ *lp = l;
+ return 1;
+}
+
+static int
+getdisp(Instr *ip, int mod, int rm, int code)
+{
+ uchar c;
+ ushort s;
+
+ if (mod > 2)
+ return 1;
+ if (mod == 1) {
+ if (igetc(ip, &c) < 0)
+ return -1;
+ if (c&0x80)
+ ip->disp = c|0xffffff00;
+ else
+ ip->disp = c&0xff;
+ } else if (mod == 2 || rm == code) {
+ if (ip->asize == 'E') {
+ if (igetl(ip, &ip->disp) < 0)
+ return -1;
+ } else {
+ if (igets(ip, &s) < 0)
+ return -1;
+ if (s&0x8000)
+ ip->disp = s|0xffff0000;
+ else
+ ip->disp = s;
+ }
+ if (mod == 0)
+ ip->base = -1;
+ }
+ return 1;
+}
+
+static int
+modrm(Instr *ip, uchar c)
+{
+ uchar rm, mod;
+
+ mod = (c>>6)&3;
+ rm = c&7;
+ ip->mod = mod;
+ ip->base = rm;
+ ip->reg = (c>>3)&7;
+ if (mod == 3) /* register */
+ return 1;
+ if (ip->asize == 0) { /* 16-bit mode */
+ switch(rm)
+ {
+ case 0:
+ ip->base = BX; ip->index = SI;
+ break;
+ case 1:
+ ip->base = BX; ip->index = DI;
+ break;
+ case 2:
+ ip->base = BP; ip->index = SI;
+ break;
+ case 3:
+ ip->base = BP; ip->index = DI;
+ break;
+ case 4:
+ ip->base = SI;
+ break;
+ case 5:
+ ip->base = DI;
+ break;
+ case 6:
+ ip->base = BP;
+ break;
+ case 7:
+ ip->base = BX;
+ break;
+ default:
+ break;
+ }
+ return getdisp(ip, mod, rm, 6);
+ }
+ if (rm == 4) { /* scummy sib byte */
+ if (igetc(ip, &c) < 0)
+ return -1;
+ ip->ss = (c>>6)&0x03;
+ ip->index = (c>>3)&0x07;
+ if (ip->index == 4)
+ ip->index = -1;
+ ip->base = c&0x07;
+ return getdisp(ip, mod, ip->base, 5);
+ }
+ return getdisp(ip, mod, rm, 5);
+}
+
+static Optable *
+mkinstr(Instr *ip, ulong pc)
+{
+ int i, n;
+ uchar c;
+ ushort s;
+ Optable *op, *obase;
+ char buf[128];
+
+ memset(ip, 0, sizeof(*ip));
+ ip->base = -1;
+ ip->index = -1;
+ ip->osize = 'L';
+ ip->asize = 'E';
+ ip->addr = pc;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ obase = optable;
+newop:
+ op = &obase[c];
+ if (op->proto == 0) {
+badop:
+ n = snprint(buf, sizeof(buf), "opcode: ??");
+ for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+ _hexify(buf+n, ip->mem[i], 1);
+ strcpy(buf+n, "??");
+ kwerrstr(buf);
+ return 0;
+ }
+ for(i = 0; i < 2 && op->operand[i]; i++) {
+ switch(op->operand[i])
+ {
+ case Ib: /* 8-bit immediate - (no sign extension)*/
+ if (igetc(ip, &c) < 0)
+ return 0;
+ ip->imm = c&0xff;
+ break;
+ case Jbs: /* 8-bit jump immediate (sign extended) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c&0xff;
+ ip->jumptype = Jbs;
+ break;
+ case Ibs: /* 8-bit immediate (sign extended) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ if (ip->osize == 'L')
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c|0xff00;
+ else
+ ip->imm = c&0xff;
+ break;
+ case Iw: /* 16-bit immediate -> imm */
+ if (igets(ip, &s) < 0)
+ return 0;
+ ip->imm = s&0xffff;
+ ip->jumptype = Iw;
+ break;
+ case Iw2: /* 16-bit immediate -> in imm2*/
+ if (igets(ip, &s) < 0)
+ return 0;
+ ip->imm2 = s&0xffff;
+ break;
+ case Iwd: /* Operand-sized immediate (no sign extension)*/
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Awd: /* Address-sized immediate (no sign extension)*/
+ if (ip->asize == 'E') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Iwds: /* Operand-sized immediate (sign extended) */
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ if (s&0x8000)
+ ip->imm = s|0xffff0000;
+ else
+ ip->imm = s&0xffff;
+ }
+ ip->jumptype = Iwds;
+ break;
+ case OA: /* literal 0x0a byte */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c != 0x0a)
+ goto badop;
+ break;
+ case R0: /* base register must be R0 */
+ if (ip->base != 0)
+ goto badop;
+ break;
+ case R1: /* base register must be R1 */
+ if (ip->base != 1)
+ goto badop;
+ break;
+ case RMB: /* R/M field with byte register (/r)*/
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ ip->osize = 'B';
+ break;
+ case RM: /* R/M field with register (/r) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case RMOPB: /* R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ c = ip->reg; /* secondary op code */
+ obase = (Optable*)op->proto;
+ ip->osize = 'B';
+ goto newop;
+ case RMOP: /* R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMOP: /* FP R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = ip->reg+8; /* 16 entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMEX: /* Extended FP R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = (c&0x3f)+8; /* 64-entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case RMR: /* R/M register only (mod = 11) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) != 0xc0) {
+ kwerrstr("invalid R/M register: %x", c);
+ return 0;
+ }
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case RMM: /* R/M register only (mod = 11) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0) {
+ kwerrstr("invalid R/M memory mode: %x", c);
+ return 0;
+ }
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->disp) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->disp = s&0xffff;
+ }
+ if (igets(ip, (ushort*)&ip->seg) < 0)
+ return 0;
+ ip->jumptype = PTR;
+ break;
+ case AUX: /* Multi-byte op code - Auxiliary table */
+ obase = (Optable*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case PRE: /* Instr Prefix */
+ ip->prefix = (char*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case SEG: /* Segment Prefix */
+ ip->segment = (char*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case OPOVER: /* Operand size override */
+ ip->osize = 'W';
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case ADDOVER: /* Address size override */
+ ip->asize = 0;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case JUMP: /* mark instruction as JUMP or RET */
+ case RET:
+ ip->jumptype = op->operand[i];
+ break;
+ default:
+ kwerrstr("bad operand type %d", op->operand[i]);
+ return 0;
+ }
+ }
+ return op;
+}
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+ va_end(arg);
+}
+
+/*
+ * if we want to call 16 bit regs AX,BX,CX,...
+ * and 32 bit regs EAX,EBX,ECX,... then
+ * change the defs of ANAME and ONAME to:
+ * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
+ * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
+ */
+#define ANAME(ip) ""
+#define ONAME(ip) ""
+
+static char *reg[] = {
+ "AX",
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+ int offset;
+
+ offset = ip->disp;
+
+ bprint(ip, "%lux(SP)", offset);
+}
+
+static void
+pea(Instr *ip)
+{
+ if (ip->mod == 3) {
+ if (ip->osize == 'B')
+ bprint(ip, breg[ip->base]);
+ else
+ bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+ return;
+ }
+ if (ip->segment)
+ bprint(ip, ip->segment);
+ if (ip->asize == 'E' && ip->base == SP)
+ plocal(ip);
+ else {
+ bprint(ip,"%lux", ip->disp);
+ if (ip->base >= 0)
+ bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]);
+ }
+ if (ip->index >= 0)
+ bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
+}
+
+static void
+immediate(Instr *ip, long val)
+{
+ bprint(ip, "%lux", val);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+ if (ip->prefix)
+ bprint(ip, "%s ", ip->prefix);
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%')
+ *ip->curr++ = *fmt;
+ else switch(*++fmt)
+ {
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'A':
+ bprint(ip, "%s", ANAME(ip));
+ break;
+ case 'C':
+ bprint(ip, "CR%d", ip->reg);
+ break;
+ case 'D':
+ if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "DR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'I':
+ bprint(ip, "$");
+ immediate(ip, ip->imm2);
+ break;
+ case 'O':
+ bprint(ip,"%s", ONAME(ip));
+ break;
+ case 'i':
+ bprint(ip, "$");
+ immediate(ip,ip->imm);
+ break;
+ case 'R':
+ bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
+ break;
+ case 'S':
+ bprint(ip, "%c", ip->osize);
+ break;
+ case 'T':
+ if (ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "TR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'X':
+ if (ip->osize == 'L')
+ bprint(ip,"CWDE");
+ else
+ bprint(ip, "CBW");
+ break;
+ case 'd':
+ bprint(ip,"%lux:%lux",ip->seg,ip->disp);
+ break;
+ case 'e':
+ pea(ip);
+ break;
+ case 'f':
+ bprint(ip, "F%d", ip->base);
+ break;
+ case 'g':
+ if (ip->reg < 6)
+ bprint(ip,"%s",sreg[ip->reg]);
+ else
+ bprint(ip,"???");
+ break;
+ case 'p':
+ immediate(ip, ip->imm+ip->addr+ip->n);
+ break;
+ case 'r':
+ if (ip->osize == 'B')
+ bprint(ip,"%s",breg[ip->reg]);
+ else
+ bprint(ip, reg[ip->reg]);
+ break;
+ case 'x':
+ if (ip->osize == 'L')
+ bprint(ip,"CDQ");
+ else
+ bprint(ip, "CWD");
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+int
+i386inst(ulong pc, char modifier, char *buf, int n)
+{
+ Instr instr;
+ Optable *op;
+
+ USED(modifier);
+ op = mkinstr(&instr, pc);
+ if (op == 0) {
+ kgerrstr(buf, n);
+ return -1;
+ }
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ prinstr(&instr, op->proto);
+ return instr.n;
+}
+
+int
+i386das(ulong pc, char *buf, int n)
+{
+ Instr instr;
+ int i;
+
+ if (mkinstr(&instr, pc) == 0) {
+ kgerrstr(buf, n);
+ return -1;
+ }
+ for(i = 0; i < instr.n && n > 2; i++) {
+ _hexify(buf, instr.mem[i], 1);
+ buf += 2;
+ n -= 2;
+ }
+ *buf = 0;
+ return instr.n;
+}
+
+int
+i386instlen(ulong pc)
+{
+ Instr i;
+
+ if (mkinstr(&i, pc))
+ return i.n;
+ return -1;
+}
+
+void
+das(uchar *x, int n)
+{
+ int l, pc;
+ char buf[128];
+/*
+ int i;
+ for(i = 0; i < n; i++)
+ print("%.2ux", x[i]);
+ print("\n");
+*/
+
+ dasdata = x;
+ pc = 0;
+ while(n > 0) {
+ i386das(pc, buf, sizeof(buf));
+ print("%.8lux %2x %-20s ", (ulong)(dasdata+pc), pc, buf);
+ l = i386inst(pc, 'i', buf, sizeof(buf));
+ print("\t%s\n", buf);
+
+ pc += l;
+ n -= l;
+ }
+}
diff --git a/libinterp/das-68000.c b/libinterp/das-68000.c
new file mode 100644
index 00000000..9676141f
--- /dev/null
+++ b/libinterp/das-68000.c
@@ -0,0 +1 @@
+#include "das-68020.c"
diff --git a/libinterp/das-68020.c b/libinterp/das-68020.c
new file mode 100644
index 00000000..baca98ec
--- /dev/null
+++ b/libinterp/das-68020.c
@@ -0,0 +1,1940 @@
+#include <lib9.h>
+#include <kernel.h>
+
+/*
+ * 68020-specific debugger interface
+ */
+
+static int m68020inst(ulong, char, char*, int);
+static int m68020das(ulong, char*, int);
+static int m68020instlen(ulong);
+
+#define werrstr print
+/*
+ * 68020 exception frames
+ */
+
+#define BPTTRAP 4 /* breakpoint gives illegal inst */
+
+static char * excep[] = {
+ [2] "bus error",
+ [3] "address error",
+ [4] "illegal instruction",
+ [5] "zero divide",
+ [6] "CHK",
+ [7] "TRAP",
+ [8] "privilege violation",
+ [9] "Trace",
+ [10] "line 1010",
+ [11] "line 1011",
+ [13] "coprocessor protocol violation",
+ [24] "spurious",
+ [25] "incon",
+ [26] "tac",
+ [27] "auto 3",
+ [28] "clock",
+ [29] "auto 5",
+ [30] "parity",
+ [31] "mouse",
+ [32] "system call",
+ [33] "system call 1",
+ [48] "FPCP branch",
+ [49] "FPCP inexact",
+ [50] "FPCP zero div",
+ [51] "FPCP underflow",
+ [52] "FPCP operand err",
+ [53] "FPCP overflow",
+ [54] "FPCP signal NAN",
+};
+
+static int m68020vec;
+static
+struct ftype{
+ short fmt;
+ short len;
+ char *name;
+} ftype[] = { /* section 6.5.7 page 6-24 */
+ { 0, 4*2, "Short Format" },
+ { 1, 4*2, "Throwaway" },
+ { 2, 6*2, "Instruction Exception" },
+ { 3, 6*2, "MC68040 Floating Point Exception" },
+ { 8, 29*2, "MC68010 Bus Fault" },
+ { 7, 30*2, "MC68040 Bus Fault" },
+ { 9, 10*2, "Coprocessor mid-Instruction" },
+ { 10, 16*2, "MC68020 Short Bus Fault" },
+ { 11, 46*2, "MC68020 Long Bus Fault" },
+ { 0, 0, 0 }
+};
+static uchar *dasdata;
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+ /* 68020 Disassembler and related functions */
+/*
+not supported: cpBcc, cpDBcc, cpGEN, cpScc, cpTRAPcc, cpRESTORE, cpSAVE
+
+opcode: 1 1 1 1 1 1
+ 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+%y - register number x x x
+%f - trap vector x x x
+%e - destination eff addr x x x x x x
+%p - conditional predicate x x x x x x
+%s - size code x x
+%C - cache code x x
+%E - source eff addr. x x x x x x
+%d - direction bit x
+%c - condition code x x x x
+%x - register number x x x
+%b - shift count x x x
+%q - daffy 3-bit quick operand or shift count x x x
+%i - immediate operand <varies>
+%t - offset(PC) <varies>
+
+word 1: 1 1 1 1 1 1
+ 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+%a - register number x x x
+%w - bit field width x x x x x
+%L - MMU function code (SFC/DFC/D%a/#[0-3]) x x x x x
+%P - conditional predicate x x x x x x
+%k - k factor x x x x x x x
+%m - register mask x x x x x x x x
+%N - control register id x x x x x x x x x x x x
+%j - (Dq != Dr) ? Dq:Dr : Dr x x x x x x
+%K - dynamic k register x x x
+%h - register number x x x
+%I - MMU function code mask x x x x
+%o - bit field offset x x x x x
+%u - register number x x x
+%D - float dest reg x x x
+%F - (fdr==fsr) ? "F%D" :"F%B,F%D" x x x x x x
+%S - float source type x x x
+%B - float source register x x x
+%Z - ATC level number x x x
+%H - MMU register x x x x
+%r - register type/number x x x x
+
+word 2: 1 1 1 1 1 1
+ 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+%A - register number x x x
+%U - register number x x x
+%R - register type,number x x x x
+
+-----------------------------------------------------------------------------
+
+%a - register [word 1: 0-2]
+%c - condition code [opcode: 8-11]
+%d - direction [opcode: 8]
+%e - destination effective address [opcode: 0-5]
+%f - trap vector [opcode: 0-3]
+%h - register [word 1: 5-7]
+%i - immediate operand (1, 2, or 4 bytes)
+%j - Dq:Dr if Dq != Dr; else Dr => Dr [word 1: 0-2] Dq [word 1: 12-14]
+%k - k factor [word 1: 0-6]
+%m - register mask [word 1: 0-7]
+%o - bit field offset [word 1: 6-10]
+%p - conditional predicate [opcode: 0-5]
+%q - daffy 3-bit quick operand [opcode: 9-11]
+%r - register type, [word 1: 15], register [word 1: 12-14]
+%s - size [opcode: 6-7]
+%t - offset beyond pc (text address) (2 or 4 bytes)
+%u - register [word 1: 6-8]
+%w - bit field width [word 1: 0-4]
+%x - register [opcode: 9-11]
+%y - register [opcode: 0-2]
+%A - register [word 2: 0-2]
+%B - float source register [word 1: 10-12]
+%C - cache identifier [opcode: 6-7] (IC, DC, or BC)
+%D - float dest reg [word 1: 7-9]
+%E - dest effective address [opcode: 6-11]
+%F - float dest reg == float src reg => "F%D"; else "F%B,F%D"
+%H - MMU reg [word 1: 10-13] (see above & p 4-53/54)
+%I - MMU function code mask [word 1: 5-8]
+%K - dynamic k factor register [word 1: 4-6]
+%L - MMU function code [word 1: 0-4] (SFC, DFC, D%a, or #[0-3])
+%N - control register [word 1: 0-11]
+%P - conditional predicate [word 1: 0-5]
+%R - register type, [word 2: 15], register [word 2: 12-14]
+%S - float source type code [word 1: 10-12]
+%U - register [word 2: 6-8]
+%Z - ATC level number [word 1: 10-12]
+%1 - Special case: EA as second operand
+*/
+ /* Operand classes */
+enum {
+ EAPI = 1, /* extended address: pre decrement only */
+ EACA, /* extended address: control alterable */
+ EACAD, /* extended address: control alterable or Dreg */
+ EACAPI, /* extended address: control alterable or post-incr */
+ EACAPD, /* extended address: control alterable or pre-decr */
+ EAMA, /* extended address: memory alterable */
+ EADA, /* extended address: data alterable */
+ EAA, /* extended address: alterable */
+ EAC, /* extended address: control addressing */
+ EACPI, /* extended address: control addressing or post-incr */
+ EACD, /* extended address: control addressing or Dreg */
+ EAD, /* extended address: data addressing */
+ EAM, /* extended address: memory addressing */
+ EAM_B, /* EAM with byte immediate data */
+ EADI, /* extended address: data addressing or immediate */
+ EADI_L, /* EADI with long immediate data */
+ EADI_W, /* EADI with word immediate data */
+ EAALL, /* extended address: all modes */
+ EAALL_L, /* EAALL with long immediate data */
+ EAALL_W, /* EAALL with word immediate data */
+ EAALL_B, /* EAALL with byte immediate date */
+ /* special codes not directly used for validation */
+ EAFLT, /* extended address: EADI for B, W, L, or S; else EAM */
+ EADDA, /* destination extended address: EADA */
+ BREAC, /* EAC operand for JMP or CALL */
+ OP8, /* low 8 bits of op word */
+ I8, /* low 8-bits of first extension word */
+ I16, /* 16 bits in first extension word */
+ I32, /* 32 bits in first and second extension words */
+ IV, /* 8, 16 or 32 bit data in first & 2nd extension words */
+ C16, /* CAS2 16 bit immediate with bits 9-11 & 3-5 zero */
+ BR8, /* 8 bits in op word or 16 or 32 bits in extension words
+ branch instruction format (p. 2-25) */
+ BR16, /* 16-bit branch displacement */
+ BR32, /* 32-bit branch displacement */
+ STACK, /* return PC on stack - follow set only */
+};
+ /* validation bit masks for various EA classes */
+enum {
+ Dn = 0x0001, /* Data register */
+ An = 0x0002, /* Address register */
+ Ind = 0x0004, /* Address register indirect */
+ Pinc = 0x0008, /* Address register indirect post-increment */
+ Pdec = 0x0010, /* Address register indirect pre-decrement */
+ Bdisp = 0x0020, /* Base/Displacement in all its forms */
+ PCrel = 0x0040, /* PC relative addressing in all its forms */
+ Imm = 0x0080, /* Immediate data */
+ Abs = 0x0100, /* Absolute */
+};
+ /* EA validation table indexed by operand class number */
+
+static short validea[] =
+{
+ 0, /* none */
+ Pdec, /* EAPI */
+ Abs|Bdisp|Ind, /* EACA */
+ Abs|Bdisp|Ind|Dn, /* EACAD */
+ Abs|Bdisp|Pinc|Ind, /* EACAPI */
+ Abs|Bdisp|Pdec|Ind, /* EACAPD */
+ Abs|Bdisp|Pdec|Pinc|Ind, /* EAMA */
+ Abs|Bdisp|Pdec|Pinc|Ind|Dn, /* EADA */
+ Abs|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAA */
+ Abs|PCrel|Bdisp|Ind, /* EAC */
+ Abs|PCrel|Bdisp|Pinc|Ind, /* EACPI */
+ Abs|PCrel|Bdisp|Ind|Dn, /* EACD */
+ Abs|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EAD */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind, /* EAM */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind, /* EAM_B */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI_L */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI_W */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_L */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_W */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_B */
+};
+ /* EA types */
+enum
+{
+ Dreg, /* Dn */
+ Areg, /* An */
+ AInd, /* (An) */
+ APdec, /* -(An) */
+ APinc, /* (An)+ */
+ ADisp, /* Displacement beyond (An) */
+ BXD, /* Base, Index, Displacement */
+ PDisp, /* Displacement beyond PC */
+ PXD, /* PC, Index, Displacement */
+ ABS, /* absolute */
+ IMM, /* immediate */
+ IREAL, /* single precision real immediate */
+ IEXT, /* extended precision real immediate */
+ IPACK, /* packed real immediate */
+ IDBL, /* double precision real immediate */
+};
+
+typedef struct optable Optable;
+typedef struct operand Operand;
+typedef struct inst Inst;
+
+struct optable
+{
+ ushort opcode;
+ ushort mask0;
+ ushort op2;
+ ushort mask1;
+ char opdata[2];
+ char *format;
+};
+
+struct operand
+{
+ int eatype;
+ short ext;
+ union {
+ long immediate; /* sign-extended integer byte/word/long */
+ struct { /* index mode displacements */
+ long disp;
+ long outer;
+ };
+ char floater[24]; /* floating point immediates */
+ };
+};
+
+struct inst
+{
+ int n; /* # bytes in instruction */
+ ulong addr; /* addr of start of instruction */
+ ushort raw[4+12]; /* longest instruction: 24 byte packed immediate */
+ Operand and[2];
+ char *end; /* end of print buffer */
+ char *curr; /* current fill point in buffer */
+ char *errmsg;
+};
+ /* class 0: bit field, MOVEP & immediate instructions */
+static Optable t0[] = {
+{ 0x003c, 0xffff, 0x0000, 0xff00, {I8}, "ORB %i,CCR" },
+{ 0x007c, 0xffff, 0x0000, 0x0000, {I16}, "ORW %i,SR" },
+{ 0x023c, 0xffff, 0x0000, 0xff00, {I8}, "ANDB %i,CCR" },
+{ 0x027c, 0xffff, 0x0000, 0x0000, {I16}, "ANDW %i,SR" },
+{ 0x0a3c, 0xffff, 0x0000, 0xff00, {I8}, "EORB %i,CCR" },
+{ 0x0a7c, 0xffff, 0x0000, 0x0000, {I16}, "EORW %i,SR" },
+{ 0x0cfc, 0xffff, 0x0000, 0x0000, {C16,C16}, "CAS2W R%a:R%A,R%u:R%U,(%r):(%R)"} ,
+{ 0x0efc, 0xffff, 0x0000, 0x0000, {C16,C16}, "CAS2L R%a:R%A,R%u:R%U,(%r):(%R)"} ,
+
+{ 0x06c0, 0xfff8, 0x0000, 0x0000, {0}, "RTM R%y" },
+{ 0x06c8, 0xfff8, 0x0000, 0x0000, {0}, "RTM A%y" },
+{ 0x0800, 0xfff8, 0x0000, 0x0000, {I16}, "BTSTL %i,R%y" },
+{ 0x0840, 0xfff8, 0x0000, 0x0000, {I16}, "BCHGL %i,R%y" },
+{ 0x0880, 0xfff8, 0x0000, 0x0000, {I16}, "BCLRL %i,R%y" },
+
+{ 0x00c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2B %e,%r" },
+{ 0x00c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2B %e,%r" },
+{ 0x02c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2W %e,%r" },
+{ 0x02c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2W %e,%r" },
+{ 0x04c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2L %e,%r" },
+{ 0x04c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2L %e,%r" },
+{ 0x06c0, 0xffc0, 0x0000, 0x0000, {I16, BREAC}, "CALLM %i,%e" },
+{ 0x0800, 0xffc0, 0x0000, 0x0000, {I16, EAD}, "BTSTB %i,%e" },
+{ 0x0840, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BCHG %i,%e" },
+{ 0x0880, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BCLR %i,%e" },
+{ 0x08c0, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BSET %i,%e" },
+{ 0x0ac0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASB R%a,R%u,%e" },
+{ 0x0cc0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASW R%a,R%u,%e" },
+{ 0x0ec0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASL R%a,R%u,%e" },
+
+{ 0x0000, 0xff00, 0x0000, 0x0000, {IV, EADA}, "OR%s %i,%e" },
+{ 0x0200, 0xff00, 0x0000, 0x0000, {IV, EADA}, "AND%s %i,%e" },
+{ 0x0400, 0xff00, 0x0000, 0x0000, {IV, EADA}, "SUB%s %i,%e" },
+{ 0x0600, 0xff00, 0x0000, 0x0000, {IV, EADA}, "ADD%s %i,%e" },
+{ 0x0a00, 0xff00, 0x0000, 0x0000, {IV, EADA}, "EOR%s %i,%e" },
+{ 0x0c00, 0xff00, 0x0000, 0x0000, {IV, EAD}, "CMP%s %i,%e" },
+{ 0x0e00, 0xff00, 0x0000, 0x0800, {EAMA}, "MOVES%s %e,%r" },
+{ 0x0e00, 0xff00, 0x0800, 0x0800, {EAMA}, "MOVES%s %r,%e" },
+
+{ 0x0108, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPW (%i,A%y),R%x" },
+{ 0x0148, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPL (%i,A%y),R%x" },
+{ 0x0188, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPW R%x,(%i,A%y)" },
+{ 0x01c8, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPL R%x,(%i,A%y)" },
+{ 0x0100, 0xf1f8, 0x0000, 0x0000, {0}, "BTSTL R%x,R%y" },
+{ 0x0140, 0xf1f8, 0x0000, 0x0000, {0}, "BCHGL R%x,R%y" },
+{ 0x0180, 0xf1f8, 0x0000, 0x0000, {0}, "BCLRL R%x,R%y" },
+{ 0x01c0, 0xf1f8, 0x0000, 0x0000, {0}, "BSET R%x,R%y" },
+
+{ 0x0100, 0xf1c0, 0x0000, 0x0000, {EAM_B}, "BTSTB R%x,%e" },
+{ 0x0140, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BCHG R%x,%e" },
+{ 0x0180, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BCLR R%x,%e" },
+{ 0x01c0, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BSET R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 1: move byte */
+static Optable t1[] = {
+{ 0x1000, 0xf000, 0x0000, 0x0000, {EAALL_B,EADDA},"MOVB %e,%E" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 2: move long */
+static Optable t2[] = {
+{ 0x2040, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "MOVL %e,A%x" },
+
+{ 0x2000, 0xf000, 0x0000, 0x0000, {EAALL_L,EADDA},"MOVL %e,%E" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 3: move word */
+static Optable t3[] = {
+{ 0x3040, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "MOVW %e,A%x" },
+
+{ 0x3000, 0xf000, 0x0000, 0x0000, {EAALL_W,EADDA},"MOVW %e,%E" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 4: miscellaneous */
+static Optable t4[] = {
+{ 0x4e75, 0xffff, 0x0000, 0x0000, {STACK}, "RTS" },
+{ 0x4e77, 0xffff, 0x0000, 0x0000, {STACK}, "RTR" },
+{ 0x4afc, 0xffff, 0x0000, 0x0000, {0}, "ILLEGAL" },
+{ 0x4e71, 0xffff, 0x0000, 0x0000, {0}, "NOP" },
+{ 0x4e74, 0xffff, 0x0000, 0x0000, {I16, STACK}, "RTD %i" },
+{ 0x4e76, 0xffff, 0x0000, 0x0000, {0}, "TRAPV" },
+{ 0x4e70, 0xffff, 0x0000, 0x0000, {0}, "RESET" },
+{ 0x4e72, 0xffff, 0x0000, 0x0000, {I16}, "STOP %i" },
+{ 0x4e73, 0xffff, 0x0000, 0x0000, {0}, "RTE" },
+{ 0x4e7a, 0xffff, 0x0000, 0x0000, {I16}, "MOVEL %N,%r" },
+{ 0x4e7b, 0xffff, 0x0000, 0x0000, {I16}, "MOVEL %r,%N" },
+
+{ 0x4808, 0xfff8, 0x0000, 0x0000, {I32}, "LINKL A%y,%i" },
+{ 0x4840, 0xfff8, 0x0000, 0x0000, {0}, "SWAPW R%y" },
+{ 0x4848, 0xfff8, 0x0000, 0x0000, {0}, "BKPT #%y" },
+{ 0x4880, 0xfff8, 0x0000, 0x0000, {0}, "EXTW R%y" },
+{ 0x48C0, 0xfff8, 0x0000, 0x0000, {0}, "EXTL R%y" },
+{ 0x49C0, 0xfff8, 0x0000, 0x0000, {0}, "EXTBL R%y" },
+{ 0x4e50, 0xfff8, 0x0000, 0x0000, {I16}, "LINKW A%y,%i" },
+{ 0x4e58, 0xfff8, 0x0000, 0x0000, {0}, "UNLK A%y" },
+{ 0x4e60, 0xfff8, 0x0000, 0x0000, {0}, "MOVEL (A%y),USP" },
+{ 0x4e68, 0xfff8, 0x0000, 0x0000, {0}, "MOVEL USP,(A%y)" },
+
+{ 0x4e40, 0xfff0, 0x0000, 0x0000, {0}, "SYS %f" },
+
+{ 0x40c0, 0xffc0, 0x0000, 0x0000, {EADA}, "MOVW SR,%e" },
+{ 0x42c0, 0xffc0, 0x0000, 0x0000, {EADA}, "MOVW CCR,%e" },
+{ 0x44c0, 0xffc0, 0x0000, 0x0000, {EADI_W}, "MOVW %e,CCR" },
+{ 0x46c0, 0xffc0, 0x0000, 0x0000, {EADI_W}, "MOVW %e,SR" },
+{ 0x4800, 0xffc0, 0x0000, 0x0000, {EADA}, "NBCDB %e" },
+{ 0x4840, 0xffc0, 0x0000, 0x0000, {EAC}, "PEA %e" },
+{ 0x4880, 0xffc0, 0x0000, 0x0000, {I16, EACAPD},"MOVEMW %i,%e" },
+{ 0x48c0, 0xffc0, 0x0000, 0x0000, {I16, EACAPD},"MOVEML %i,%e" },
+{ 0x4ac0, 0xffc0, 0x0000, 0x0000, {EADA}, "TAS %e" },
+{ 0x4a00, 0xffc0, 0x0000, 0x0000, {EAD}, "TSTB %e" },
+{ 0x4c00, 0xffc0, 0x0000, 0x8ff8, {EADI_L}, "MULUL %e,%r" },
+{ 0x4c00, 0xffc0, 0x0400, 0x8ff8, {EADI_L}, "MULUL %e,R%a:%r" },
+{ 0x4c00, 0xffc0, 0x0800, 0x8ff8, {EADI_L}, "MULSL %e,%r" },
+{ 0x4c00, 0xffc0, 0x0c00, 0x8ff8, {EADI_L}, "MULSL %e,R%a:%r" },
+{ 0x4c40, 0xffc0, 0x0000, 0x8ff8, {EADI_L}, "DIVUL %e,%j" },
+{ 0x4c40, 0xffc0, 0x0400, 0x8ff8, {EADI_L}, "DIVUD %e,%r:R%a" },
+{ 0x4c40, 0xffc0, 0x0800, 0x8ff8, {EADI_L}, "DIVSL %e,%j" },
+{ 0x4c40, 0xffc0, 0x0c00, 0x8ff8, {EADI_L}, "DIVSD %e,%r:R%a" },
+{ 0x4c80, 0xffc0, 0x0000, 0x0000, {I16, EACPI}, "MOVEMW %1,%i" },
+{ 0x4cc0, 0xffc0, 0x0000, 0x0000, {I16, EACPI}, "MOVEML %1,%i" },
+{ 0x4e80, 0xffc0, 0x0000, 0x0000, {BREAC}, "JSR %e" },
+{ 0x4ec0, 0xffc0, 0x0000, 0x0000, {BREAC}, "JMP %e" },
+
+{ 0x4000, 0xff00, 0x0000, 0x0000, {EADA}, "NEGX%s %e" },
+{ 0x4200, 0xff00, 0x0000, 0x0000, {EADA}, "CLR%s %e" },
+{ 0x4400, 0xff00, 0x0000, 0x0000, {EADA}, "NEG%s %e" },
+{ 0x4600, 0xff00, 0x0000, 0x0000, {EADA}, "NOT%s %e" },
+{ 0x4a00, 0xff00, 0x0000, 0x0000, {EAALL}, "TST%s %e" },
+
+{ 0x4180, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "CHKW %e,R%x" },
+{ 0x41c0, 0xf1c0, 0x0000, 0x0000, {EAC}, "LEA %e,A%x" },
+{ 0x4100, 0xf1c0, 0x0000, 0x0000, {EADI_L}, "CHKL %e,R%x" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 5: miscellaneous quick, branch & trap instructions */
+static Optable t5[] = {
+{ 0x5000, 0xf1c0, 0x0000, 0x0000, {EADA}, "ADDB $Q#%q,%e" },
+{ 0x5100, 0xf1c0, 0x0000, 0x0000, {EADA}, "SUBB $Q#%q,%e" },
+
+{ 0x50c8, 0xf1f8, 0x0000, 0x0000, {BR16}, "DB%c R%y,%t" },
+{ 0x51c8, 0xf1f8, 0x0000, 0x0000, {BR16}, "DB%c R%y,%t" },
+
+{ 0x5000, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDB $Q#%q,%e" },
+{ 0x5040, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDW $Q#%q,%e" },
+{ 0x5080, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDL $Q#%q,%e" },
+{ 0x5100, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBB $Q#%q,%e" },
+{ 0x5140, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBW $Q#%q,%e" },
+{ 0x5180, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBL $Q#%q,%e" },
+
+{ 0x50fa, 0xf0ff, 0x0000, 0x0000, {I16}, "TRAP%cW %i" },
+{ 0x50fb, 0xf0ff, 0x0000, 0x0000, {I32}, "TRAP%cL %i" },
+{ 0x50fc, 0xf0ff, 0x0000, 0x0000, {0}, "TRAP%c" },
+
+{ 0x50c0, 0xf0c0, 0x0000, 0x0000, {EADA}, "S%c %e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 6: branch instructions */
+static Optable t6[] = {
+{ 0x6000, 0xff00, 0x0000, 0x0000, {BR8}, "BRA %t" },
+{ 0x6100, 0xff00, 0x0000, 0x0000, {BR8}, "BSR %t" },
+{ 0x6000, 0xf000, 0x0000, 0x0000, {BR8}, "B%c %t" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 7: move quick */
+static Optable t7[] = {
+{ 0x7000, 0xf100, 0x0000, 0x0000, {OP8}, "MOVL $Q%i,R%x" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 8: BCD operations, DIV, and OR instructions */
+static Optable t8[] = {
+{ 0x8100, 0xf1f8, 0x0000, 0x0000, {0}, "SBCDB R%y,R%x" },
+{ 0x8108, 0xf1f8, 0x0000, 0x0000, {0}, "SBCDB -(A%y),-(A%x)" },
+{ 0x8140, 0xf1f8, 0x0000, 0x0000, {I16}, "PACK R%y,R%x,%i" },
+{ 0x8148, 0xf1f8, 0x0000, 0x0000, {I16}, "PACK -(A%y),-(A%x),%i" },
+{ 0x8180, 0xf1f8, 0x0000, 0x0000, {I16}, "UNPK R%y,R%x,%i" },
+{ 0x8188, 0xf1f8, 0x0000, 0x0000, {I16}, "UNPK -(A%y),-(A%x),%i" },
+
+{ 0x80c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "DIVUW %e,R%x" },
+{ 0x81c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "DIVSW %e,R%x" },
+
+{ 0x8000, 0xf100, 0x0000, 0x0000, {EADI}, "OR%s %e,R%x" },
+{ 0x8100, 0xf100, 0x0000, 0x0000, {EAMA}, "OR%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 9: subtract instruction */
+static Optable t9[] = {
+{ 0x90c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "SUBW %e,A%x" },
+{ 0x91c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "SUBL %e,A%x" },
+
+{ 0x9100, 0xf138, 0x0000, 0x0000, {0}, "SUBX%s R%y,R%x" },
+{ 0x9108, 0xf138, 0x0000, 0x0000, {0}, "SUBX%s -(A%y),-(A%x)" },
+
+{ 0x9000, 0xf100, 0x0000, 0x0000, {EAALL}, "SUB%s %e,R%x" },
+{ 0x9100, 0xf100, 0x0000, 0x0000, {EAMA}, "SUB%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class b: CMP & EOR */
+static Optable tb[] = {
+{ 0xb000, 0xf1c0, 0x0000, 0x0000, {EADI}, "CMPB R%x,%e" },
+{ 0xb040, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "CMPW R%x,%e" },
+{ 0xb080, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "CMPL R%x,%e" },
+{ 0xb0c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "CMPW A%x,%e" },
+{ 0xb1c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "CMPL A%x,%e" },
+
+{ 0xb108, 0xf138, 0x0000, 0x0000, {0}, "CMP%s (A%y)+,(A%x)+" },
+
+{ 0xb100, 0xf100, 0x0000, 0x0000, {EADA}, "EOR%s %e,R%x" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class c: AND, MUL, BCD & Exchange */
+static Optable tc[] = {
+{ 0xc100, 0xf1f8, 0x0000, 0x0000, {0}, "ABCDB R%y,R%x" },
+{ 0xc108, 0xf1f8, 0x0000, 0x0000, {0}, "ABCDB -(A%y),-(A%x)" },
+{ 0xc140, 0xf1f8, 0x0000, 0x0000, {0}, "EXG R%x,R%y" },
+{ 0xc148, 0xf1f8, 0x0000, 0x0000, {0}, "EXG A%x,A%y" },
+{ 0xc188, 0xf1f8, 0x0000, 0x0000, {0}, "EXG R%x,A%y" },
+
+{ 0xc0c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "MULUW %e,R%x" },
+{ 0xc1c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "MULSW %e,R%x" },
+
+{ 0xc000, 0xf100, 0x0000, 0x0000, {EADI}, "AND%s %e,R%x" },
+{ 0xc100, 0xf100, 0x0000, 0x0000, {EAMA}, "AND%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class d: addition */
+static Optable td[] = {
+{ 0xd000, 0xf1c0, 0x0000, 0x0000, {EADI}, "ADDB %e,R%x" },
+{ 0xd0c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "ADDW %e,A%x" },
+{ 0xd1c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "ADDL %e,A%x" },
+
+{ 0xd100, 0xf138, 0x0000, 0x0000, {0}, "ADDX%s R%y,R%x" },
+{ 0xd108, 0xf138, 0x0000, 0x0000, {0}, "ADDX%s -(A%y),-(A%x)" },
+
+{ 0xd000, 0xf100, 0x0000, 0x0000, {EAALL}, "ADD%s %e,R%x" },
+{ 0xd100, 0xf100, 0x0000, 0x0000, {EAMA}, "ADD%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class e: shift, rotate, bit field operations */
+static Optable te[] = {
+{ 0xe8c0, 0xffc0, 0x0820, 0xfe38, {EACD}, "BFTST %e{R%u:R%a}" },
+{ 0xe8c0, 0xffc0, 0x0800, 0xfe20, {EACD}, "BFTST %e{R%u:%w}" },
+{ 0xe8c0, 0xffc0, 0x0020, 0xf838, {EACD}, "BFTST %e{%o:R%a}" },
+{ 0xe8c0, 0xffc0, 0x0000, 0xf820, {EACD}, "BFTST %e{%o:%w}" },
+
+{ 0xe9c0, 0xffc0, 0x0820, 0x8e38, {EACD}, "BFEXTU %e{R%u:R%a},%r" },
+{ 0xe9c0, 0xffc0, 0x0800, 0x8e20, {EACD}, "BFEXTU %e{R%u:%w},%r" },
+{ 0xe9c0, 0xffc0, 0x0020, 0x8838, {EACD}, "BFEXTU %e{%o:R%a},%r" },
+{ 0xe9c0, 0xffc0, 0x0000, 0x8820, {EACD}, "BFEXTU %e{%o:%w},%r" },
+
+{ 0xeac0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFCHG %e{R%u:R%a}" },
+{ 0xeac0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFCHG %e{R%u:%w}" },
+{ 0xeac0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFCHG %e{%o:R%a}" },
+{ 0xeac0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFCHG %e{%o:%w}" },
+
+{ 0xebc0, 0xffc0, 0x0820, 0x8e38, {EACD}, "BFEXTS %e{R%u:R%a},%r" },
+{ 0xebc0, 0xffc0, 0x0800, 0x8e20, {EACD}, "BFEXTS %e{R%u:%w},%r" },
+{ 0xebc0, 0xffc0, 0x0020, 0x8838, {EACD}, "BFEXTS %e{%o:R%a},%r" },
+{ 0xebc0, 0xffc0, 0x0000, 0x8820, {EACD}, "BFEXTS %e{%o:%w},%r" },
+
+{ 0xecc0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFCLR %e{R%u:R%a}" },
+{ 0xecc0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFCLR %e{R%u:%w}" },
+{ 0xecc0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFCLR %e{%o:R%a}" },
+{ 0xecc0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFCLR %e{%o:%w}" },
+
+{ 0xedc0, 0xffc0, 0x0820, 0x8e38, {EACAD}, "BFFFO %e{R%u:R%a},%r" },
+{ 0xedc0, 0xffc0, 0x0800, 0x8e20, {EACAD}, "BFFFO %e{R%u:%w},%r" },
+{ 0xedc0, 0xffc0, 0x0020, 0x8838, {EACAD}, "BFFFO %e{%o:R%a},%r" },
+{ 0xedc0, 0xffc0, 0x0000, 0x8820, {EACAD}, "BFFFO %e{%o:%w},%r" },
+
+{ 0xeec0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFSET %e{R%u:R%a}" },
+{ 0xeec0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFSET %e{R%u:%w}" },
+{ 0xeec0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFSET %e{%o:R%a}" },
+{ 0xeec0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFSET %e{%o:%w}" },
+
+{ 0xefc0, 0xffc0, 0x0820, 0x8e38, {EACAD}, "BFINS %r,%e{R%u:R%a}" },
+{ 0xefc0, 0xffc0, 0x0800, 0x8e20, {EACAD}, "BFINS %r,%e{R%u:%w}" },
+{ 0xefc0, 0xffc0, 0x0020, 0x8838, {EACAD}, "BFINS %r,%e{%o:R%a}" },
+{ 0xefc0, 0xffc0, 0x0000, 0x8820, {EACAD}, "BFINS %r,%e{%o:%w}" },
+
+{ 0xe0c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "AS%dW %e" },
+{ 0xe2c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "LS%dW %e" },
+{ 0xe4c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "ROX%dW %e" },
+{ 0xe6c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "RO%dW %e" },
+
+{ 0xe000, 0xf038, 0x0000, 0x0000, {0}, "AS%d%s #%q,R%y" },
+{ 0xe008, 0xf038, 0x0000, 0x0000, {0}, "LS%d%s #%q,R%y" },
+{ 0xe010, 0xf038, 0x0000, 0x0000, {0}, "ROX%d%s #%q,R%y" },
+{ 0xe018, 0xf038, 0x0000, 0x0000, {0}, "RO%d%s #%q,R%y" },
+{ 0xe020, 0xf038, 0x0000, 0x0000, {0}, "AS%d%s R%x,R%y" },
+{ 0xe028, 0xf038, 0x0000, 0x0000, {0}, "LS%d%s R%x,R%y" },
+{ 0xe030, 0xf038, 0x0000, 0x0000, {0}, "ROX%d%s R%x,R%y" },
+{ 0xe038, 0xf038, 0x0000, 0x0000, {0}, "RO%d%s R%x,R%y" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class f: coprocessor and mmu instructions */
+static Optable tf[] = {
+{ 0xf280, 0xffff, 0x0000, 0xffff, {0}, "FNOP" },
+{ 0xf200, 0xffff, 0x5c00, 0xfc00, {0}, "FMOVECRX %k,F%D" },
+{ 0xf27a, 0xffff, 0x0000, 0xffc0, {I16}, "FTRAP%P %i" },
+{ 0xf27b, 0xffff, 0x0000, 0xffc0, {I32}, "FTRAP%P %i" },
+{ 0xf27c, 0xffff, 0x0000, 0xffc0, {0}, "FTRAP%P" },
+
+{ 0xf248, 0xfff8, 0x0000, 0xffc0, {BR16}, "FDB%P R%y,%t" },
+{ 0xf620, 0xfff8, 0x8000, 0x8fff, {0}, "MOVE16 (A%y)+,(%r)+" },
+{ 0xf500, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHN (A%y)" },
+{ 0xf508, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSH (A%y)" },
+{ 0xf510, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHAN" },
+{ 0xf518, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHA" },
+{ 0xf548, 0xfff8, 0x0000, 0x0000, {0}, "PTESTW (A%y)" },
+{ 0xf568, 0xfff8, 0x0000, 0x0000, {0}, "PTESTR (A%y)" },
+{ 0xf600, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 (A%y)+,$%i" },
+{ 0xf608, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 $%i,(A%y)-" },
+{ 0xf610, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 (A%y),$%i" },
+{ 0xf618, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 $%i,(A%y)" },
+
+{ 0xf000, 0xffc0, 0x0800, 0xffff, {EACA}, "PMOVE %e,TT0" },
+{ 0xf000, 0xffc0, 0x0900, 0xffff, {EACA}, "PMOVEFD %e,TT0" },
+{ 0xf000, 0xffc0, 0x0a00, 0xffff, {EACA}, "PMOVE TT0,%e" },
+{ 0xf000, 0xffc0, 0x0b00, 0xffff, {EACA}, "PMOVEFD TT0,%e" },
+{ 0xf000, 0xffc0, 0x0c00, 0xffff, {EACA}, "PMOVE %e,TT1" },
+{ 0xf000, 0xffc0, 0x0d00, 0xffff, {EACA}, "PMOVEFD %e,TT1" },
+{ 0xf000, 0xffc0, 0x0e00, 0xffff, {EACA}, "PMOVE TT1,%e" },
+{ 0xf000, 0xffc0, 0x0f00, 0xffff, {EACA}, "PMOVEFD TT1,%e" },
+{ 0xf000, 0xffc0, 0x2400, 0xffff, {0}, "PFLUSHA" },
+{ 0xf000, 0xffc0, 0x2800, 0xffff, {EACA}, "PVALID VAL,%e" },
+{ 0xf000, 0xffc0, 0x6000, 0xffff, {EACA}, "PMOVE %e,MMUSR" },
+{ 0xf000, 0xffc0, 0x6200, 0xffff, {EACA}, "PMOVE MMUSR,%e" },
+{ 0xf000, 0xffc0, 0x2800, 0xfff8, {EACA}, "PVALID A%a,%e" },
+{ 0xf000, 0xffc0, 0x2000, 0xffe0, {EACA}, "PLOADW %L,%e" },
+{ 0xf000, 0xffc0, 0x2200, 0xffe0, {EACA}, "PLOADR %L,%e" },
+{ 0xf000, 0xffc0, 0x8000, 0xffe0, {EACA}, "PTESTW %L,%e,#0" },
+{ 0xf000, 0xffc0, 0x8200, 0xffe0, {EACA}, "PTESTR %L,%e,#0" },
+{ 0xf000, 0xffc0, 0x3000, 0xfe00, {0}, "PFLUSH %L,#%I" },
+{ 0xf000, 0xffc0, 0x3800, 0xfe00, {EACA}, "PFLUSH %L,#%I,%e" },
+{ 0xf000, 0xffc0, 0x8000, 0xe300, {EACA}, "PTESTW %L,%e,#%Z" },
+{ 0xf000, 0xffc0, 0x8100, 0xe300, {EACA}, "PTESTW %L,%e,#%Z,A%h" },
+{ 0xf000, 0xffc0, 0x8200, 0xe300, {EACA}, "PTESTR %L,%e,#%Z" },
+{ 0xf000, 0xffc0, 0x8300, 0xe300, {EACA}, "PTESTR %L,%e,#%Z,A%h" },
+{ 0xf000, 0xffc0, 0x4000, 0xc3ff, {EACA}, "PMOVE %e,%H" },
+{ 0xf000, 0xffc0, 0x4100, 0xc3ff, {EACA}, "PMOVEFD %e,%H" },
+{ 0xf000, 0xffc0, 0x4200, 0xc3ff, {EACA}, "PMOVE %H,%e" },
+
+ /* floating point (coprocessor 1)*/
+
+{ 0xf200, 0xffc0, 0x8400, 0xffff, {EAALL_L}, "FMOVEL %e,FPIAR" },
+{ 0xf200, 0xffc0, 0x8800, 0xffff, {EADI_L}, "FMOVEL %e,FPSR" },
+{ 0xf200, 0xffc0, 0x9000, 0xffff, {EADI_L}, "FMOVEL %e,FPCR" },
+{ 0xf200, 0xffc0, 0xa400, 0xffff, {EAA}, "FMOVEL FPIAR,%e" },
+{ 0xf200, 0xffc0, 0xa800, 0xffff, {EADA}, "FMOVEL FPSR,%e" },
+{ 0xf200, 0xffc0, 0xb000, 0xffff, {EADA}, "FMOVEL FPCR,%e" },
+
+{ 0xf240, 0xffc0, 0x0000, 0xffc0, {EADA}, "FS%P %e" },
+
+{ 0xf200, 0xffc0, 0xd000, 0xff00, {EACPI}, "FMOVEMX %e,%m" },
+{ 0xf200, 0xffc0, 0xd800, 0xff00, {EACPI}, "FMOVEMX %e,R%K" },
+{ 0xf200, 0xffc0, 0xe000, 0xff00, {EAPI}, "FMOVEMX %m,-(A%y)" },
+{ 0xf200, 0xffc0, 0xe800, 0xff00, {EAPI}, "FMOVEMX R%K,-(A%y)" },
+{ 0xf200, 0xffc0, 0xf000, 0xff00, {EACAPD}, "FMOVEMX %m,%e" },
+{ 0xf200, 0xffc0, 0xf800, 0xff00, {EACAPD}, "FMOVEMX R%K,%e" },
+
+{ 0xf200, 0xffc0, 0x6800, 0xfc00, {EAMA}, "FMOVEX F%D,%e" },
+{ 0xf200, 0xffc0, 0x6c00, 0xfc00, {EAMA}, "FMOVEP F%D,%e,{%k}" },
+{ 0xf200, 0xffc0, 0x7400, 0xfc00, {EAMA}, "FMOVED F%D,%e" },
+{ 0xf200, 0xffc0, 0x7c00, 0xfc00, {EAMA}, "FMOVEP F%D,%e,{R%K}" },
+
+{ 0xf200, 0xffc0, 0x8000, 0xe3ff, {EAM}, "FMOVEML #%B,%e" },
+{ 0xf200, 0xffc0, 0xa000, 0xe3ff, {EAMA}, "FMOVEML %e,#%B" },
+
+{ 0xf200, 0xffc0, 0x0000, 0xe07f, {0}, "FMOVE F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0001, 0xe07f, {0}, "FINTX %F" },
+{ 0xf200, 0xffc0, 0x0002, 0xe07f, {0}, "FSINHX %F" },
+{ 0xf200, 0xffc0, 0x0003, 0xe07f, {0}, "FINTRZ %F" },
+{ 0xf200, 0xffc0, 0x0004, 0xe07f, {0}, "FSQRTX %F" },
+{ 0xf200, 0xffc0, 0x0006, 0xe07f, {0}, "FLOGNP1X %F" },
+{ 0xf200, 0xffc0, 0x0009, 0xe07f, {0}, "FTANHX %F" },
+{ 0xf200, 0xffc0, 0x000a, 0xe07f, {0}, "FATANX %F" },
+{ 0xf200, 0xffc0, 0x000c, 0xe07f, {0}, "FASINX %F" },
+{ 0xf200, 0xffc0, 0x000d, 0xe07f, {0}, "FATANHX %F" },
+{ 0xf200, 0xffc0, 0x000e, 0xe07f, {0}, "FSINX %F" },
+{ 0xf200, 0xffc0, 0x000f, 0xe07f, {0}, "FTANX %F" },
+{ 0xf200, 0xffc0, 0x0010, 0xe07f, {0}, "FETOXX %F" },
+{ 0xf200, 0xffc0, 0x0011, 0xe07f, {0}, "FTWOTOXX %F" },
+{ 0xf200, 0xffc0, 0x0012, 0xe07f, {0}, "FTENTOXX %F" },
+{ 0xf200, 0xffc0, 0x0014, 0xe07f, {0}, "FLOGNX %F" },
+{ 0xf200, 0xffc0, 0x0015, 0xe07f, {0}, "FLOG10X %F" },
+{ 0xf200, 0xffc0, 0x0016, 0xe07f, {0}, "FLOG2X %F" },
+{ 0xf200, 0xffc0, 0x0018, 0xe07f, {0}, "FABSX %F" },
+{ 0xf200, 0xffc0, 0x0019, 0xe07f, {0}, "FCOSHX %F" },
+{ 0xf200, 0xffc0, 0x001a, 0xe07f, {0}, "FNEGX %F" },
+{ 0xf200, 0xffc0, 0x001c, 0xe07f, {0}, "FACOSX %F" },
+{ 0xf200, 0xffc0, 0x001d, 0xe07f, {0}, "FCOSX %F" },
+{ 0xf200, 0xffc0, 0x001e, 0xe07f, {0}, "FGETEXPX %F" },
+{ 0xf200, 0xffc0, 0x001f, 0xe07f, {0}, "FGETMANX %F" },
+{ 0xf200, 0xffc0, 0x0020, 0xe07f, {0}, "FDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0021, 0xe07f, {0}, "FMODX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0022, 0xe07f, {0}, "FADDX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0023, 0xe07f, {0}, "FMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0024, 0xe07f, {0}, "FSGLDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0025, 0xe07f, {0}, "FREMX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0026, 0xe07f, {0}, "FSCALEX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0027, 0xe07f, {0}, "FSGLMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0028, 0xe07f, {0}, "FSUBX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0038, 0xe07f, {0}, "FCMPX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x003a, 0xe07f, {0}, "FTSTX F%B" },
+{ 0xf200, 0xffc0, 0x0040, 0xe07f, {0}, "FSMOVE F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0041, 0xe07f, {0}, "FSSQRTX %F"},
+{ 0xf200, 0xffc0, 0x0044, 0xe07f, {0}, "FDMOVE F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0045, 0xe07f, {0}, "FDSQRTX %F" },
+{ 0xf200, 0xffc0, 0x0058, 0xe07f, {0}, "FSABSX %F" },
+{ 0xf200, 0xffc0, 0x005a, 0xe07f, {0}, "FSNEGX %F" },
+{ 0xf200, 0xffc0, 0x005c, 0xe07f, {0}, "FDABSX %F" },
+{ 0xf200, 0xffc0, 0x005e, 0xe07f, {0}, "FDNEGX %F" },
+{ 0xf200, 0xffc0, 0x0060, 0xe07f, {0}, "FSDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0062, 0xe07f, {0}, "FSADDX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0063, 0xe07f, {0}, "FSMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0064, 0xe07f, {0}, "FDDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0066, 0xe07f, {0}, "FDADDX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0067, 0xe07f, {0}, "FDMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0068, 0xe07f, {0}, "FSSUBX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x006c, 0xe07f, {0}, "FDSUBX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x4000, 0xe07f, {EAFLT}, "FMOVE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4001, 0xe07f, {EAFLT}, "FINT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4002, 0xe07f, {EAFLT}, "FSINH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4003, 0xe07f, {EAFLT}, "FINTRZ%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4004, 0xe07f, {EAFLT}, "FSQRT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4006, 0xe07f, {EAFLT}, "FLOGNP1%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4009, 0xe07f, {EAFLT}, "FTANH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400a, 0xe07f, {EAFLT}, "FATAN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400c, 0xe07f, {EAFLT}, "FASIN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400d, 0xe07f, {EAFLT}, "FATANH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400e, 0xe07f, {EAFLT}, "FSIN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400f, 0xe07f, {EAFLT}, "FTAN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4010, 0xe07f, {EAFLT}, "FETOX%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4011, 0xe07f, {EAFLT}, "FTWOTOX%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4012, 0xe07f, {EAFLT}, "FTENTOX%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4014, 0xe07f, {EAFLT}, "FLOGN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4015, 0xe07f, {EAFLT}, "FLOG10%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4016, 0xe07f, {EAFLT}, "FLOG2%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4018, 0xe07f, {EAFLT}, "FABS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4019, 0xe07f, {EAFLT}, "FCOSH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401a, 0xe07f, {EAFLT}, "FNEG%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401c, 0xe07f, {EAFLT}, "FACOS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401d, 0xe07f, {EAFLT}, "FCOS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401e, 0xe07f, {EAFLT}, "FGETEXP%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401f, 0xe07f, {EAFLT}, "FGETMAN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4020, 0xe07f, {EAFLT}, "FDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4021, 0xe07f, {EAFLT}, "FMOD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4022, 0xe07f, {EAFLT}, "FADD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4023, 0xe07f, {EAFLT}, "FMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4024, 0xe07f, {EAFLT}, "FSGLDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4025, 0xe07f, {EAFLT}, "FREM%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4026, 0xe07f, {EAFLT}, "FSCALE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4027, 0xe07f, {EAFLT}, "FSGLMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4028, 0xe07f, {EAFLT}, "FSUB%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4038, 0xe07f, {EAFLT}, "FCMP%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x403a, 0xe07f, {EAFLT}, "FTST%S %e" },
+{ 0xf200, 0xffc0, 0x4040, 0xe07f, {EAFLT}, "FSMOVE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4041, 0xe07f, {EAFLT}, "FSSQRT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4044, 0xe07f, {EAFLT}, "FDMOVE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4045, 0xe07f, {EAFLT}, "FDSQRT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4058, 0xe07f, {EAFLT}, "FSABS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x405a, 0xe07f, {EAFLT}, "FSNEG%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x405c, 0xe07f, {EAFLT}, "FDABS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x405e, 0xe07f, {EAFLT}, "FDNEG%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4060, 0xe07f, {EAFLT}, "FSDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4062, 0xe07f, {EAFLT}, "FSADD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4063, 0xe07f, {EAFLT}, "FSMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4064, 0xe07f, {EAFLT}, "FDDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4066, 0xe07f, {EAFLT}, "FDADD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4067, 0xe07f, {EAFLT}, "FDMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4068, 0xe07f, {EAFLT}, "FSSUB%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x406c, 0xe07f, {EAFLT}, "FDSUB%S %e,F%D" },
+
+{ 0xf200, 0xffc0, 0x0030, 0xe078, {0}, "FSINCOSX F%B,F%a:F%D" },
+{ 0xf200, 0xffc0, 0x4030, 0xe078, {EAFLT}, "FSINCOS%S %e,F%a:F%D" },
+
+{ 0xf200, 0xffc0, 0x6000, 0xe000, {EADA}, "FMOVE%S F%D,%e" },
+
+{ 0xf300, 0xffc0, 0x0000, 0x0000, {EACAPD}, "FSAVE %e" },
+{ 0xf340, 0xffc0, 0x0000, 0x0000, {EACAPI}, "FRESTORE %e" },
+
+{ 0xf280, 0xffc0, 0x0000, 0x0000, {BR16}, "FB%p %t" },
+{ 0xf2c0, 0xffc0, 0x0000, 0x0000, {BR32}, "FB%p %t" },
+
+{ 0xf408, 0xff38, 0x0000, 0x0000, {0}, "CINVL %C,(A%y)" },
+{ 0xf410, 0xff38, 0x0000, 0x0000, {0}, "CINVP %C,(A%y)" },
+{ 0xf418, 0xff38, 0x0000, 0x0000, {0}, "CINVA %C" },
+{ 0xf428, 0xff38, 0x0000, 0x0000, {0}, "CPUSHL %C,(A%y)" },
+{ 0xf430, 0xff38, 0x0000, 0x0000, {0}, "CPUSHP %C,(A%y)" },
+{ 0xf438, 0xff38, 0x0000, 0x0000, {0}, "CPUSHA %C" },
+{ 0,0,0,0,{0},0 },
+};
+
+static Optable *optables[] =
+{
+ t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, 0, tb, tc, td, te, tf,
+};
+
+static int
+dumpinst(Inst *ip, char *buf, int n)
+{
+ int i;
+
+ if (n <= 0)
+ return 0;
+
+ *buf++ = '#';
+ for (i = 0; i < ip->n && i*4+1 < n-4; i++, buf += 4)
+ _hexify(buf, ip->raw[i], 3);
+ *buf = 0;
+ return i*4+1;
+}
+
+static int
+get2(long offset, ushort *buf) {
+ buf[0]=((ushort*)dasdata)[offset/2];
+ return 2;
+}
+
+static int
+get1(long offset, uchar *buf,int size) {
+ memmove(buf,&dasdata[offset],size);
+ return 1;
+}
+
+static int
+getword(Inst *ip, long offset)
+{
+ if (ip->n < nelem(ip->raw)) {
+ if (get2(offset, &ip->raw[ip->n++]) > 0)
+ return 1;
+ werrstr("can't read instruction: %r");
+ } else
+ werrstr("instruction too big: %r");
+ return -1;
+}
+
+static int
+getshorts(Inst *ip, void *where, int n)
+{
+ if (ip->n+n < nelem(ip->raw)) {
+ if (get1(ip->addr+ip->n*2, (uchar*)&ip->raw[ip->n], n*2) < 0) {
+ werrstr("can't read instruction: %r");
+ return 0;
+ }
+ memmove(where, &ip->raw[ip->n], n*2);
+ ip->n += n;
+ return 1;
+ }
+ werrstr("instruction too big: %r");
+ return 0;
+}
+
+static int
+i8(Inst *ip, long *l)
+{
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ *l = ip->raw[ip->n-1]&0xff;
+ if (*l&0x80)
+ *l |= ~0xff;
+ return 1;
+}
+
+static int
+i16(Inst *ip, long *l)
+{
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ *l = ip->raw[ip->n-1];
+ if (*l&0x8000)
+ *l |= ~0xffff;
+ return 1;
+}
+static int
+i32(Inst *ip, long *l)
+{
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ *l = (ip->raw[ip->n-2]<<16)|ip->raw[ip->n-1];
+ return 1;
+}
+
+static int
+getimm(Inst *ip, Operand *ap, int mode)
+{
+ ap->eatype = IMM;
+ switch(mode)
+ {
+ case EAM_B: /* byte */
+ case EAALL_B:
+ return i8(ip, &ap->immediate);
+ case EADI_W: /* word */
+ case EAALL_W:
+ return i16(ip, &ap->immediate);
+ case EADI_L: /* long */
+ case EAALL_L:
+ return i32(ip, &ap->immediate);
+ case EAFLT: /* floating point - size in bits 10-12 or word 1 */
+ switch((ip->raw[1]>>10)&0x07)
+ {
+ case 0: /* long integer */
+ return i32(ip, &ap->immediate);
+ case 1: /* single precision real */
+ ap->eatype = IREAL;
+ return getshorts(ip, ap->floater, 2);
+ case 2: /* extended precision real - not supported */
+ ap->eatype = IEXT;
+ return getshorts(ip, ap->floater, 6);
+ case 3: /* packed decimal real - not supported */
+ ap->eatype = IPACK;
+ return getshorts(ip, ap->floater, 12);
+ case 4: /* integer word */
+ return i16(ip, &ap->immediate);
+ case 5: /* double precision real */
+ ap->eatype = IDBL;
+ return getshorts(ip, ap->floater, 4);
+ case 6: /* integer byte */
+ return i8(ip, &ap->immediate);
+ default:
+ ip->errmsg = "bad immediate float data";
+ return -1;
+ }
+ break;
+ case IV: /* size encoded in bits 6&7 of opcode word */
+ default:
+ switch((ip->raw[0]>>6)&0x03)
+ {
+ case 0x00: /* integer byte */
+ return i8(ip, &ap->immediate);
+ case 0x01: /* integer word */
+ return i16(ip, &ap->immediate);
+ case 0x02: /* integer long */
+ return i32(ip, &ap->immediate);
+ default:
+ ip->errmsg = "bad immediate size";
+ return -1;
+ }
+ break;
+ }
+ return 1;
+}
+
+static int
+getdisp(Inst *ip, Operand *ap)
+{
+ short ext;
+
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ ext = ip->raw[ip->n-1];
+ ap->ext = ext;
+ if ((ext&0x100) == 0) { /* indexed with 7-bit displacement */
+ ap->disp = ext&0x7f;
+ if (ap->disp&0x40)
+ ap->disp |= ~0x7f;
+ return 1;
+ }
+ switch(ext&0x30) /* first (inner) displacement */
+ {
+ case 0x10:
+ break;
+ case 0x20:
+ if (i16(ip, &ap->disp) < 0)
+ return -1;
+ break;
+ case 0x30:
+ if (i32(ip, &ap->disp) < 0)
+ return -1;
+ break;
+ default:
+ ip->errmsg = "bad EA displacement";
+ return -1;
+ }
+ switch (ext&0x03) /* outer displacement */
+ {
+ case 0x02: /* 16 bit displacement */
+ return i16(ip, &ap->outer);
+ case 0x03: /* 32 bit displacement */
+ return i32(ip, &ap->outer);
+ default:
+ break;
+ }
+ return 1;
+}
+
+static int
+ea(Inst *ip, int ea, Operand *ap, int mode)
+{
+ int type, size;
+
+ type = 0;
+ ap->ext = 0;
+ switch((ea>>3)&0x07)
+ {
+ case 0x00:
+ ap->eatype = Dreg;
+ type = Dn;
+ break;
+ case 0x01:
+ ap->eatype = Areg;
+ type = An;
+ break;
+ case 0x02:
+ ap->eatype = AInd;
+ type = Ind;
+ break;
+ case 0x03:
+ ap->eatype = APinc;
+ type = Pinc;
+ break;
+ case 0x04:
+ ap->eatype = APdec;
+ type = Pdec;
+ break;
+ case 0x05:
+ ap->eatype = ADisp;
+ type = Bdisp;
+ if (i16(ip, &ap->disp) < 0)
+ return -1;
+ break;
+ case 0x06:
+ ap->eatype = BXD;
+ type = Bdisp;
+ if (getdisp(ip, ap) < 0)
+ return -1;
+ break;
+ case 0x07:
+ switch(ea&0x07)
+ {
+ case 0x00:
+ type = Abs;
+ ap->eatype = ABS;
+ if (i16(ip, &ap->immediate) < 0)
+ return -1;
+ break;
+ case 0x01:
+ type = Abs;
+ ap->eatype = ABS;
+ if (i32(ip, &ap->immediate) < 0)
+ return -1;
+ break;
+ case 0x02:
+ type = PCrel;
+ ap->eatype = PDisp;
+ if (i16(ip, &ap->disp) < 0)
+ return -1;
+ break;
+ case 0x03:
+ type = PCrel;
+ ap->eatype = PXD;
+ if (getdisp(ip, ap) < 0)
+ return -1;
+ break;
+ case 0x04:
+ type = Imm;
+ if (getimm(ip, ap, mode) < 0)
+ return -1;
+ break;
+ default:
+ ip->errmsg = "bad EA mode";
+ return -1;
+ }
+ }
+ /* Allowable floating point EAs are restricted for packed,
+ * extended, and double precision operands
+ */
+ if (mode == EAFLT) {
+ size = (ip->raw[1]>>10)&0x07;
+ if (size == 2 || size == 3 || size == 5)
+ mode = EAM;
+ else
+ mode = EADI;
+ }
+ if (!(validea[mode]&type)) {
+ ip->errmsg = "invalid EA";
+ return -1;
+ }
+ return 1;
+}
+
+static int
+decode(Inst *ip, Optable *op)
+{
+ int i, t, mode;
+ Operand *ap;
+ short opcode;
+
+ opcode = ip->raw[0];
+ for (i = 0; i < nelem(op->opdata) && op->opdata[i]; i++) {
+ ap = &ip->and[i];
+ mode = op->opdata[i];
+ switch(mode)
+ {
+ case EAPI: /* normal EA modes */
+ case EACA:
+ case EACAD:
+ case EACAPI:
+ case EACAPD:
+ case EAMA:
+ case EADA:
+ case EAA:
+ case EAC:
+ case EACPI:
+ case EACD:
+ case EAD:
+ case EAM:
+ case EAM_B:
+ case EADI:
+ case EADI_L:
+ case EADI_W:
+ case EAALL:
+ case EAALL_L:
+ case EAALL_W:
+ case EAALL_B:
+ case EAFLT:
+ if (ea(ip, opcode&0x3f, ap, mode) < 0)
+ return -1;
+ break;
+ case EADDA: /* stupid bit flop required */
+ t = ((opcode>>9)&0x07)|((opcode>>3)&0x38);
+ if (ea(ip, t, ap, EADA)< 0)
+ return -1;
+ break;
+ case BREAC: /* EAC JMP or CALL operand */
+ if (ea(ip, opcode&0x3f, ap, EAC) < 0)
+ return -1;
+ break;
+ case OP8: /* weird movq instruction */
+ ap->eatype = IMM;
+ ap->immediate = opcode&0xff;
+ if (opcode&0x80)
+ ap->immediate |= ~0xff;
+ break;
+ case I8: /* must be two-word opcode */
+ ap->eatype = IMM;
+ ap->immediate = ip->raw[1]&0xff;
+ if (ap->immediate&0x80)
+ ap->immediate |= ~0xff;
+ break;
+ case I16: /* 16 bit immediate */
+ case BR16:
+ ap->eatype = IMM;
+ if (i16(ip, &ap->immediate) < 0)
+ return -1;
+ break;
+ case C16: /* CAS2 16 bit immediate */
+ ap->eatype = IMM;
+ if (i16(ip, &ap->immediate) < 0)
+ return -1;
+ if (ap->immediate & 0x0e38) {
+ ip->errmsg = "bad CAS2W operand";
+ return 0;
+ }
+ break;
+ case I32: /* 32 bit immediate */
+ case BR32:
+ ap->eatype = IMM;
+ if (i32(ip, &ap->immediate) < 0)
+ return -1;
+ break;
+ case IV: /* immediate data depends on size field */
+ if (getimm(ip, ap, IV) < 0)
+ return -1;
+ break;
+ case BR8: /* branch displacement format */
+ ap->eatype = IMM;
+ ap->immediate = opcode&0xff;
+ if (ap->immediate == 0) {
+ if (i16(ip, &ap->immediate) < 0)
+ return -1;
+ } else if (ap->immediate == 0xff) {
+ if (i32(ip, &ap->immediate) < 0)
+ return -1;
+ } else if (ap->immediate & 0x80)
+ ap->immediate |= ~0xff;
+ break;
+ case STACK: /* Dummy operand type for Return instructions */
+ default:
+ break;
+ }
+ }
+ return 1;
+}
+
+static Optable *
+instruction(Inst *ip)
+{
+ ushort opcode, op2;
+ Optable *op;
+ int class;
+
+ ip->n = 0;
+ if (getword(ip, ip->addr) < 0)
+ return 0;
+ opcode = ip->raw[0];
+ if (get2(ip->addr+2, &op2) < 0)
+ op2 = 0;
+ class = (opcode>>12)&0x0f;
+ for (op = optables[class]; op && op->format; op++) {
+ if (op->opcode != (opcode&op->mask0))
+ continue;
+ if (op->op2 != (op2&op->mask1))
+ continue;
+ if (op->mask1)
+ ip->raw[ip->n++] = op2;
+ return op;
+ }
+ ip->errmsg = "Invalid opcode";
+ return 0;
+}
+
+static void
+bprint(Inst *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static char *regname[] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "A0",
+ "A1", "A2", "A3", "A4", "A5", "A6", "A7", "PC", "SB"
+};
+
+#define CANY 0
+#define CTEXT 0
+
+int
+symoff(char *buf, int n, long v, int)
+{
+ return snprint(buf, n, "%lux", v);
+}
+static void
+plocal(Inst *ip, Operand *ap)
+{
+ bprint(ip, "%lux", ap->disp);
+}
+
+/*
+ * this guy does all the work of printing the base and index component
+ * of an EA.
+ */
+static int
+pidx(Inst *ip, int ext, int reg, char *bfmt, char *ifmt, char *nobase)
+{
+ char *s;
+ int printed;
+ char buf[512];
+
+ printed = 1;
+ if (ext&0x80) { /* Base suppressed */
+ if (reg == 16)
+ bprint(ip, bfmt, "(ZPC)");
+ else if (nobase)
+ bprint(ip, nobase);
+ else
+ printed = 0;
+ } else /* format base reg */
+ bprint(ip, bfmt, regname[reg]);
+ if (ext & 0x40) /* index suppressed */
+ return printed;
+ switch ((ext>>9)&0x03)
+ {
+ case 0x01:
+ s = "*2";
+ break;
+ case 0x02:
+ s = "*4";
+ break;
+ case 0x03:
+ s = "*8";
+ break;
+ default:
+ if (ext&0x80)
+ s = "*1";
+ else
+ s = "";
+ break;
+ }
+ sprint(buf, "%s.%c%s", regname[(ext>>12)&0x0f], (ext&0x800) ? 'L' : 'W', s);
+ if (!printed)
+ bprint(ip, ifmt, buf);
+ else
+ bprint(ip, "(%s)", buf);
+ return 1;
+}
+
+static void
+prindex(Inst *ip, int reg, Operand *ap)
+{
+ short ext;
+ int left;
+ int disp;
+
+ left = ip->end-ip->curr;
+ if (left <= 0)
+ return;
+ ext = ap->ext;
+ disp = ap->disp;
+ /* look for static base register references */
+ if ((ext&0x100) == 0) { /* brief form */
+ if (reg == 15)
+ plocal(ip, ap);
+ else if (disp)
+ ip->curr += symoff(ip->curr, left, disp, CANY);
+ pidx(ip, ext&0xff00, reg, "(%s)", "(%s)", 0);
+ return;
+ }
+ switch(ext&0x3f) /* bd size, && i/is */
+ {
+ case 0x10:
+ if (!pidx(ip, ext, reg, "(%s)", "(%s)", 0))
+ bprint(ip, "#0");
+ break;
+ case 0x11:
+ if (pidx(ip, ext, reg, "((%s)", "((%s)", 0))
+ bprint(ip, ")");
+ else
+ bprint(ip, "#0");
+ break;
+ case 0x12:
+ case 0x13:
+ ip->curr += symoff(ip->curr, left, ap->outer, CANY);
+ if (pidx(ip, ext, reg, "((%s)", "((%s)", 0))
+ bprint(ip, ")");
+ break;
+ case 0x15:
+ if (!pidx(ip, ext, reg, "((%s))", "(%s)", 0))
+ bprint(ip, "#0");
+ break;
+ case 0x16:
+ case 0x17:
+ ip->curr += symoff(ip->curr, left, ap->outer, CANY);
+ pidx(ip, ext, reg, "((%s))", "(%s)", 0);
+ break;
+ case 0x20:
+ case 0x30:
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left, disp, CANY);
+ pidx(ip, ext, reg, "(%s)", "(%s)", 0);
+ break;
+ case 0x21:
+ case 0x31:
+ *ip->curr++ = '(';
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left-1, disp, CANY);
+ pidx(ip, ext, reg, "(%s)", "(%s)", 0);
+ bprint(ip, ")");
+ break;
+ case 0x22:
+ case 0x23:
+ case 0x32:
+ case 0x33:
+ ip->curr += symoff(ip->curr, left, ap->outer, CANY);
+ bprint(ip, "(");
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, ip->end-ip->curr, disp, CANY);
+ pidx(ip, ext, reg, "(%s)", "(%s)", 0);
+ bprint(ip, ")");
+ break;
+ case 0x25:
+ case 0x35:
+ *ip->curr++ = '(';
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left-1, disp, CANY);
+ if (!pidx(ip, ext, reg, "(%s))", "(%s)", "())"))
+ bprint(ip, ")");
+ break;
+ case 0x26:
+ case 0x27:
+ case 0x36:
+ case 0x37:
+ ip->curr += symoff(ip->curr, left, ap->outer, CANY);
+ bprint(ip, "(");
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, ip->end-ip->curr, disp, CANY);
+ pidx(ip, ext, reg, "(%s))", "(%s)", "())");
+ break;
+ default:
+ bprint(ip, "??%x??", ext);
+ ip->errmsg = "bad EA";
+ break;
+ }
+}
+
+static void
+pea(int reg, Inst *ip, Operand *ap)
+{
+ int i, left;
+
+ left = ip->end-ip->curr;
+ if (left < 0)
+ return;
+ switch(ap->eatype)
+ {
+ case Dreg:
+ bprint(ip, "R%d", reg);
+ break;
+ case Areg:
+ bprint(ip, "A%d", reg);
+ break;
+ case AInd:
+ bprint(ip, "(A%d)", reg);
+ break;
+ case APinc:
+ bprint(ip, "(A%d)+", reg);
+ break;
+ case APdec:
+ bprint(ip, "-(A%d)", reg);
+ break;
+ case PDisp:
+ ip->curr += symoff(ip->curr, left, ip->addr+2+ap->disp, CANY);
+ break;
+ case PXD:
+ prindex(ip, 16, ap);
+ break;
+ case ADisp:
+ ip->curr += symoff(ip->curr, left, ap->disp, CANY);
+ bprint(ip, "(A%d)", reg);
+ break;
+ case BXD:
+ prindex(ip, reg+8, ap);
+ break;
+ case ABS:
+ ip->curr += symoff(ip->curr, left, ap->immediate, CANY);
+ bprint(ip, "($0)");
+ break;
+ case IMM:
+ *ip->curr++ = '$';
+ ip->curr += symoff(ip->curr, left-1, ap->immediate, CANY);
+ break;
+ case IPACK:
+ bprint(ip, "$#");
+ for (i = 0; i < 24 && ip->curr < ip->end-1; i++) {
+ _hexify(ip->curr, ap->floater[i], 1);
+ ip->curr += 2;
+ }
+ break;
+ default:
+ bprint(ip, "??%x??", ap->eatype);
+ ip->errmsg = "bad EA type";
+ break;
+ }
+}
+
+static char *cctab[] = { "F", "T", "HI", "LS", "CC", "CS", "NE", "EQ",
+ "VC", "VS", "PL", "MI", "GE", "LT", "GT", "LE" };
+static char *fcond[] =
+{
+ "F", "EQ", "OGT", "OGE", "OLT", "OLE", "OGL", "OR",
+ "UN", "UEQ", "UGT", "UGE", "ULT", "ULE", "NE", "T",
+ "SF", "SEQ", "GT", "GE", "LT", "LE", "GL", "GLE",
+ "NGLE", "NGL", "NLE", "NLT", "NGE", "NGT", "SNE", "ST"
+};
+static char *cachetab[] = { "NC", "DC", "IC", "BC" };
+static char *mmutab[] = { "TC", "??", "SRP", "CRP" };
+static char *crtab0[] =
+{
+ "SFC", "DFC", "CACR", "TC", "ITT0", "ITT1", "DTT0", "DTT1",
+};
+static char *crtab1[] =
+{
+ "USP", "VBR", "CAAR", "MSP", "ISP", "MMUSR", "URP", "SRP",
+};
+static char typetab[] = { 'L', 'S', 'X', 'P', 'W', 'D', 'B', '?', };
+static char sztab[] = {'?', 'B', 'W', 'L', '?' };
+
+static void
+formatins(char *fmt, Inst *ip)
+{
+ short op, w1;
+ int r1, r2;
+ int currand;
+
+ op = ip->raw[0];
+ w1 = ip->raw[1];
+ currand = 0;
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%')
+ *ip->curr++ = *fmt;
+ else switch(*++fmt)
+ {
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'a': /* register number; word 1:[0-2] */
+ *ip->curr++ = (w1&0x07)+'0';
+ break;
+ case 'c': /* condition code; opcode: [8-11] */
+ bprint(ip, cctab[(op>>8)&0x0f]);
+ break;
+ case 'd': /* shift direction; opcode: [8] */
+ if (op&0x100)
+ *ip->curr++ = 'L';
+ else
+ *ip->curr++ = 'R';
+ break;
+ case 'e': /* source effective address */
+ pea(op&0x07, ip, &ip->and[currand++]);
+ break;
+ case 'f': /* trap vector; op code: [0-3] */
+ bprint(ip, "%x", op&0x0f);
+ break;
+ case 'h': /* register number; word 1: [5-7] */
+ *ip->curr++ = (w1>>5)&0x07+'0';
+ break;
+ case 'i': /* immediate operand */
+ ip->curr += symoff(ip->curr, ip->end-ip->curr,
+ ip->and[currand++].immediate, CANY);
+ break;
+ case 'j': /* data registers; word 1: [0-2] & [12-14] */
+ r1 = w1&0x07;
+ r2 = (w1>>12)&0x07;
+ if (r1 == r2)
+ bprint(ip, "R%d", r1);
+ else
+ bprint(ip, "R%d:R%d", r2, r1);
+ break;
+ case 'k': /* k factor; word 1 [0-6] */
+ bprint(ip, "%x", w1&0x7f);
+ break;
+ case 'm': /* register mask; word 1 [0-7] */
+ bprint(ip, "%x", w1&0xff);
+ break;
+ case 'o': /* bit field offset; word1: [6-10] */
+ bprint(ip, "%d", (w1>>6)&0x3f);
+ break;
+ case 'p': /* conditional predicate; opcode: [0-5]
+ only bits 0-4 are defined */
+ bprint(ip, fcond[op&0x1f]);
+ break;
+ case 'q': /* 3-bit immediate value; opcode[9-11] */
+ r1 = (op>>9)&0x07;
+ if (r1 == 0)
+ *ip->curr++ = '8';
+ else
+ *ip->curr++ = r1+'0';
+ break;
+ case 'r': /* register type & number; word 1: [12-15] */
+ bprint(ip, regname[(w1>>12)&0x0f]);
+ break;
+ case 's': /* size; opcode [6-7] */
+ *ip->curr = sztab[((op>>6)&0x03)+1];
+ if (*ip->curr++ == '?')
+ ip->errmsg = "bad size code";
+ break;
+ case 't': /* text offset */
+ ip->curr += symoff(ip->curr, ip->end-ip->curr,
+ ip->and[currand++].immediate+ip->addr+2, CTEXT);
+ break;
+ case 'u': /* register number; word 1: [6-8] */
+ *ip->curr++ = ((w1>>6)&0x07)+'0';
+ break;
+ case 'w': /* bit field width; word 1: [0-4] */
+ bprint(ip, "%d", w1&0x0f);
+ break;
+ case 'x': /* register number; opcode: [9-11] */
+ *ip->curr++ = ((op>>9)&0x07)+'0';
+ break;
+ case 'y': /* register number; opcode: [0-2] */
+ *ip->curr++ = (op&0x07)+'0';
+ break;
+ case 'z': /* shift count; opcode: [9-11] */
+ *ip->curr++ = ((op>>9)&0x07)+'0';
+ break;
+ case 'A': /* register number; word 2: [0-2] */
+ *ip->curr++ = (ip->raw[2]&0x07)+'0';
+ break;
+ case 'B': /* float source reg; word 1: [10-12] */
+ *ip->curr++ = ((w1>>10)&0x07)+'0';
+ break;
+ case 'C': /* cache identifier; opcode: [6-7] */
+ bprint(ip, cachetab[(op>>6)&0x03]);
+ break;
+ case 'D': /* float dest reg; word 1: [7-9] */
+ *ip->curr++ = ((w1>>7)&0x07)+'0';
+ break;
+ case 'E': /* destination EA; opcode: [6-11] */
+ pea((op>>9)&0x07, ip, &ip->and[currand++]);
+ break;
+ case 'F': /* float dest register(s); word 1: [7-9] & [10-12] */
+ r1 = (w1>>7)&0x07;
+ r2 = (w1>>10)&0x07;
+ if (r1 == r2)
+ bprint(ip, "F%d", r1);
+ else
+ bprint(ip, "F%d,F%d", r2, r1);
+ break;
+ case 'H': /* MMU register; word 1 [10-13] */
+ bprint(ip, mmutab[(w1>>10)&0x03]);
+ if (ip->curr[-1] == '?')
+ ip->errmsg = "bad mmu register";
+ break;
+ case 'I': /* MMU function code mask; word 1: [5-8] */
+ bprint(ip, "%x", (w1>>4)&0x0f);
+ break;
+ case 'K': /* dynamic k-factor register; word 1: [5-8] */
+ bprint(ip, "%d", (w1>>4)&0x0f);
+ break;
+ case 'L': /* MMU function code; word 1: [0-6] */
+ if (w1&0x10)
+ bprint(ip, "%x", w1&0x0f);
+ else if (w1&0x08)
+ bprint(ip, "R%d",w1&0x07);
+ else if (w1&0x01)
+ bprint(ip, "DFC");
+ else
+ bprint(ip, "SFC");
+ break;
+ case 'N': /* control register; word 1: [0-11] */
+ r1 = w1&0xfff;
+ if (r1&0x800)
+ bprint(ip, crtab1[r1&0x07]);
+ else
+ bprint(ip, crtab0[r1&0x07]);
+ break;
+ case 'P': /* conditional predicate; word 1: [0-5] */
+ bprint(ip, fcond[w1&0x1f]);
+ break;
+ case 'R': /* register type & number; word 2 [12-15] */
+ bprint(ip, regname[(ip->raw[2]>>12)&0x0f]);
+ break;
+ case 'S': /* float source type code; word 1: [10-12] */
+ *ip->curr = typetab[(w1>>10)&0x07];
+ if (*ip->curr++ == '?')
+ ip->errmsg = "bad float type";
+ break;
+ case 'U': /* register number; word 2: [6-8] */
+ *ip->curr++ = ((ip->raw[2]>>6)&0x07)+'0';
+ break;
+ case 'Z': /* ATC level number; word 1: [10-12] */
+ bprint(ip, "%x", (w1>>10)&0x07);
+ break;
+ case '1': /* effective address in second operand*/
+ pea(op&0x07, ip, &ip->and[1]);
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+static int
+dispsize(Inst *ip)
+{
+ ushort ext;
+ static int dsize[] = {0, 0, 1, 2}; /* in words */
+
+ if (get2(ip->addr+ip->n*2, &ext) < 0)
+ return -1;
+ if ((ext&0x100) == 0)
+ return 1;
+ return dsize[(ext>>4)&0x03]+dsize[ext&0x03]+1;
+}
+
+static int
+immsize(Inst *ip, int mode)
+{
+ static int fsize[] = { 2, 2, 6, 12, 1, 4, 1, -1 };
+ static int isize[] = { 1, 1, 2, -1 };
+
+ switch(mode)
+ {
+ case EAM_B: /* byte */
+ case EAALL_B:
+ case EADI_W: /* word */
+ case EAALL_W:
+ return 1;
+ case EADI_L: /* long */
+ case EAALL_L:
+ return 2;
+ case EAFLT: /* floating point - size in bits 10-12 or word 1 */
+ return fsize[(ip->raw[1]>>10)&0x07];
+ case IV: /* size encoded in bits 6&7 of opcode word */
+ default:
+ return isize[(ip->raw[0]>>6)&0x03];
+ }
+ return -1;
+}
+
+static int
+easize(Inst *ip, int ea, int mode)
+{
+ switch((ea>>3)&0x07)
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ return 0;
+ case 0x05:
+ return 1;
+ case 0x06:
+ return dispsize(ip);
+ case 0x07:
+ switch(ea&0x07)
+ {
+ case 0x00:
+ case 0x02:
+ return 1;
+ case 0x01:
+ return 2;
+ case 0x03:
+ return dispsize(ip);
+ case 0x04:
+ return immsize(ip, mode);
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+static int
+instrsize(Inst *ip, Optable *op)
+{
+ int i, t, mode;
+ short opcode;
+
+ opcode = ip->raw[0];
+ for (i = 0; i < nelem(op->opdata) && op->opdata[i]; i++) {
+ mode = op->opdata[i];
+ switch(mode)
+ {
+ case EAPI: /* normal EA modes */
+ case EACA:
+ case EACAD:
+ case EACAPI:
+ case EACAPD:
+ case EAMA:
+ case EADA:
+ case EAA:
+ case EAC:
+ case EACPI:
+ case EACD:
+ case EAD:
+ case EAM:
+ case EAM_B:
+ case EADI:
+ case EADI_L:
+ case EADI_W:
+ case EAALL:
+ case EAALL_L:
+ case EAALL_W:
+ case EAALL_B:
+ case EAFLT:
+ t = easize(ip, opcode&0x3f, mode);
+ if (t < 0)
+ return -1;
+ ip->n += t;
+ break;
+ case EADDA: /* stupid bit flop required */
+ t = ((opcode>>9)&0x07)|((opcode>>3)&0x38);
+ t = easize(ip, t, mode);
+ if (t < 0)
+ return -1;
+ ip->n += t;
+ break;
+ case BREAC: /* EAC JMP or CALL operand */
+ /* easy displacements for follow set */
+ if ((opcode&0x038) == 0x28 || (opcode&0x3f) == 0x3a) {
+ if (i16(ip, &ip->and[i].immediate) < 0)
+ return -1;
+ } else {
+ t = easize(ip, opcode&0x3f, mode);
+ if (t < 0)
+ return -1;
+ ip->n += t;
+ }
+ break;
+ case I16: /* 16 bit immediate */
+ case C16: /* CAS2 16 bit immediate */
+ ip->n++;
+ break;
+ case BR16: /* 16 bit branch displacement */
+ if (i16(ip, &ip->and[i].immediate) < 0)
+ return -1;
+ break;
+ case BR32: /* 32 bit branch displacement */
+ if (i32(ip, &ip->and[i].immediate) < 0)
+ return -1;
+ break;
+ case I32: /* 32 bit immediate */
+ ip->n += 2;
+ break;
+ case IV: /* immediate data depends on size field */
+ t = (ip->raw[0]>>6)&0x03;
+ if (t < 2)
+ ip->n++;
+ else if (t == 2)
+ ip->n += 2;
+ else
+ return -1;
+ break;
+ case BR8: /* loony branch displacement format */
+ t = opcode&0xff;
+ if (t == 0) {
+ if (i16(ip, &ip->and[i].immediate) < 0)
+ return -1;
+ } else if (t == 0xff) {
+ if (i32(ip, &ip->and[i].immediate) < 0)
+ return -1;
+ } else {
+ ip->and[i].immediate = t;
+ if (t & 0x80)
+ ip->and[i].immediate |= ~0xff;
+ }
+ break;
+ case STACK: /* Dummy operand for Return instructions */
+ case OP8: /* weird movq instruction */
+ case I8: /* must be two-word opcode */
+ default:
+ break;
+ }
+ }
+ return 1;
+}
+
+static int
+m68020instlen(ulong pc)
+{
+ Inst i;
+ Optable *op;
+
+ i.addr = pc;
+ i.errmsg = 0;
+ op = instruction(&i);
+ if (op && instrsize(&i, op) > 0)
+ return i.n*2;
+ return -1;
+}
+
+static int
+m68020inst(ulong pc, char modifier, char *buf, int n)
+{
+ Inst i;
+ Optable *op;
+
+ USED(modifier);
+ i.addr = pc;
+ i.curr = buf;
+ i.end = buf+n-1;
+ i.errmsg = 0;
+ op = instruction(&i);
+ if (!op)
+ return -1;
+ if (decode(&i, op) > 0)
+ formatins(op->format, &i);
+ if (i.errmsg) {
+ if (i.curr != buf)
+ bprint(&i, "\t\t;");
+ bprint(&i, "%s: ", i.errmsg);
+ dumpinst(&i, i.curr, i.end-i.curr);
+ }
+ return i.n*2;
+}
+
+static int
+m68020das(ulong pc, char *buf, int n)
+{
+ Inst i;
+ Optable *op;
+
+ i.addr = pc;
+ i.curr = buf;
+ i.end = buf+n-1;
+ i.errmsg = 0;
+
+ op = instruction(&i);
+ if (!op)
+ return -1;
+ decode(&i, op);
+ if (i.errmsg)
+ bprint(&i, "%s: ", i.errmsg);
+ dumpinst(&i, i.curr, i.end-i.curr);
+ return i.n*2;
+}
+
+void
+das(uchar *x, int n)
+{
+ int l, pc;
+ char buf[128];
+
+/* int i;
+ for(i = 0; i < n; i++)
+ print("%.2ux", x[i]);
+ print("\n");
+*/
+ dasdata = x;
+ pc = 0;
+ while(n > 0) {
+ if (m68020das(pc, buf, sizeof(buf))==-1)
+ sprint(buf,"illegal\t");
+ print("%.8lux %2x %-20s ", dasdata+pc, pc, buf);
+ l = m68020inst(pc, 'i', buf, sizeof(buf));
+ if (l!=-1) {
+ print("\t%s\n", buf);
+ buf[0]=0;
+
+ pc += l;
+ n -= l;
+ } else {
+ print("Illegal\n");
+ pc+=2;
+ n+=2;
+ }
+ }
+}
diff --git a/libinterp/das-arm.c b/libinterp/das-arm.c
new file mode 100644
index 00000000..9ba90112
--- /dev/null
+++ b/libinterp/das-arm.c
@@ -0,0 +1,535 @@
+#include <lib9.h>
+
+typedef struct Instr Instr;
+struct Instr
+{
+ ulong w;
+ ulong addr;
+ uchar op; /* super opcode */
+
+ uchar cond; /* bits 28-31 */
+ uchar store; /* bit 20 */
+
+ uchar rd; /* bits 12-15 */
+ uchar rn; /* bits 16-19 */
+ uchar rs; /* bits 0-11 */
+
+ long imm; /* rotated imm */
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+ char* err; /* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+ char* o;
+ void (*f)(Opcode*, Instr*);
+ char* a;
+};
+
+static void format(char*, Instr*, char*);
+static int arminst(ulong, char, char*, int);
+static int armdas(ulong, char*, int);
+
+static
+char* cond[16] =
+{
+ "EQ", "NE", "CS", "CC",
+ "MI", "PL", "VS", "VC",
+ "HI", "LS", "GE", "LT",
+ "GT", "LE", 0, "NV"
+};
+
+static
+char* shtype[4] =
+{
+ "<<", ">>", "->", "@>"
+};
+
+static int
+get4(ulong addr, long *v)
+{
+ *v = *(ulong*)addr;
+ return 1;
+}
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+int
+armclass(long w)
+{
+ int op;
+
+ op = (w >> 25) & 0x7;
+ switch(op) {
+ case 0: /* data processing r,r,r */
+ op = ((w >> 4) & 0xf);
+ if(op == 0x9) {
+ op = 48+16; /* mul */
+ if(w & (1<<24)) {
+ op += 2;
+ if(w & (1<<22))
+ op++; /* swap */
+ break;
+ }
+ if(w & (1<<21))
+ op++; /* mla */
+ break;
+ }
+ op = (w >> 21) & 0xf;
+ if(w & (1<<4))
+ op += 32;
+ else
+ if(w & (31<<7))
+ op += 16;
+ break;
+ case 1: /* data processing i,r,r */
+ op = (48) + ((w >> 21) & 0xf);
+ break;
+ case 2: /* load/store byte/word i(r) */
+ op = (48+20) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 3: /* load/store byte/word (r)(r) */
+ op = (48+20+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 4: /* block data transfer (r)(r) */
+ op = (48+20+4+4) + ((w >> 20) & 0x1);
+ break;
+ case 5: /* branch / branch link */
+ op = (48+20+4+4+2) + ((w >> 24) & 0x1);
+ break;
+ case 7: /* coprocessor crap */
+ op = (48+20+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
+ break;
+ default:
+ op = (48+20+4+4+2+2+4);
+ break;
+ }
+ return op;
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+ long w;
+
+ get4(pc, &w);
+ i->w = w;
+ i->addr = pc;
+ i->cond = (w >> 28) & 0xF;
+ i->op = armclass(w);
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+armdps(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = (i->w >> 0) & 0xf;
+ if(i->rn == 15 && i->rs == 0) {
+ if(i->op == 8) {
+ format("MOVW", i,"CPSR, R%d");
+ return;
+ } else
+ if(i->op == 10) {
+ format("MOVW", i,"SPSR, R%d");
+ return;
+ }
+ } else
+ if(i->rn == 9 && i->rd == 15) {
+ if(i->op == 9) {
+ format("MOVW", i, "R%s, CPSR");
+ return;
+ } else
+ if(i->op == 11) {
+ format("MOVW", i, "R%s, SPSR");
+ return;
+ }
+ }
+ format(o->o, i, o->a);
+}
+
+static void
+armdpi(Opcode *o, Instr *i)
+{
+ ulong v;
+ int c;
+
+ v = (i->w >> 0) & 0xff;
+ c = (i->w >> 8) & 0xf;
+ while(c) {
+ v = (v<<30) | (v>>2);
+ c--;
+ }
+ i->imm = v;
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0x0f;
+
+ /* RET is encoded as ADD #0,R14,R15 */
+ if(i->w == 0xe282f000){
+ format("RET", i, "");
+ return;
+ } else
+ format(o->o, i, o->a);
+}
+
+static void
+armsdti(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = (i->w >> 0) & 0xfff;
+ if(!(i->w & (1<<23)))
+ v = -v;
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->imm = v;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ /* convert load of offset(PC) to a load immediate */
+ if(i->rn == 15 && (i->w & (1<<20)) && get4(i->addr+v+8, &i->imm) > 0)
+ format(o->o, i, "$#%i,R%d");
+ else
+ format(o->o, i, o->a);
+}
+
+static void
+armsdts(Opcode *o, Instr *i)
+{
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->rs = (i->w >> 0) & 0xf;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ format(o->o, i, o->a);
+}
+
+static void
+armbdt(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 21) & 0x3; /* S & W bits */
+ i->rn = (i->w >> 16) & 0xf;
+ i->imm = i->w & 0xffff;
+ if(i->w == 0xe8fd8000)
+ format("RFE", i, "");
+ else
+ format(o->o, i, o->a);
+}
+
+static void
+armund(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armcdt(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armunk(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armb(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = i->w & 0xffffff;
+ if(v & 0x800000)
+ v |= ~0xffffff;
+ i->imm = (v<<2) + i->addr + 8;
+ format(o->o, i, o->a);
+}
+
+static void
+armco(Opcode *o, Instr *i) /* coprocessor instructions */
+{
+ int op, p, cp;
+
+ char buf[1024];
+
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0xf;
+ cp = (i->w >> 8) & 0xf;
+ p = (i->w >> 5) & 0x7;
+ if(i->w&0x10) {
+ op = (i->w >> 20) & 0x0f;
+ snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ } else {
+ op = (i->w >> 21) & 0x07;
+ snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ }
+ format(o->o, i, buf);
+}
+
+static Opcode opcodes[] =
+{
+ "AND%C%S", armdps, "R%s,R%n,R%d",
+ "EOR%C%S", armdps, "R%s,R%n,R%d",
+ "SUB%C%S", armdps, "R%s,R%n,R%d",
+ "RSB%C%S", armdps, "R%s,R%n,R%d",
+ "ADD%C%S", armdps, "R%s,R%n,R%d",
+ "ADC%C%S", armdps, "R%s,R%n,R%d",
+ "SBC%C%S", armdps, "R%s,R%n,R%d",
+ "RSC%C%S", armdps, "R%s,R%n,R%d",
+ "TST%C%S", armdps, "R%s,R%n,",
+ "TEQ%C%S", armdps, "R%s,R%n,",
+ "CMP%C%S", armdps, "R%s,R%n,",
+ "CMN%C%S", armdps, "R%s,R%n,",
+ "ORR%C%S", armdps, "R%s,R%n,R%d",
+ "MOVW%C%S", armdps, "R%s,R%d",
+ "BIC%C%S", armdps, "R%s,R%n,R%d",
+ "MVN%C%S", armdps, "R%s,R%d",
+
+ "AND%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "EOR%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "SUB%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "RSB%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "ADD%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "ADC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "SBC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "RSC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "TST%C%S", armdps, "(R%s%h#%m),R%n,",
+ "TEQ%C%S", armdps, "(R%s%h#%m),R%n,",
+ "CMP%C%S", armdps, "(R%s%h#%m),R%n,",
+ "CMN%C%S", armdps, "(R%s%h#%m),R%n,",
+ "ORR%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "MOVW%C%S", armdps, "(R%s%h#%m),R%d",
+ "BIC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "MVN%C%S", armdps, "(R%s%h#%m),R%d",
+
+ "AND%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "EOR%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "SUB%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "RSB%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "ADD%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "ADC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "SBC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "RSC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "TST%C%S", armdps, "(R%s%hR%m),R%n,",
+ "TEQ%C%S", armdps, "(R%s%hR%m),R%n,",
+ "CMP%C%S", armdps, "(R%s%hR%m),R%n,",
+ "CMN%C%S", armdps, "(R%s%hR%m),R%n,",
+ "ORR%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "MOVW%C%S", armdps, "(R%s%hR%m),R%d",
+ "BIC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "MVN%C%S", armdps, "(R%s%hR%m),R%d",
+
+ "AND%C%S", armdpi, "$#%i,R%n,R%d",
+ "EOR%C%S", armdpi, "$#%i,R%n,R%d",
+ "SUB%C%S", armdpi, "$#%i,R%n,R%d",
+ "RSB%C%S", armdpi, "$#%i,R%n,R%d",
+ "ADD%C%S", armdpi, "$#%i,R%n,R%d",
+ "ADC%C%S", armdpi, "$#%i,R%n,R%d",
+ "SBC%C%S", armdpi, "$#%i,R%n,R%d",
+ "RSC%C%S", armdpi, "$#%i,R%n,R%d",
+ "TST%C%S", armdpi, "$#%i,R%n,",
+ "TEQ%C%S", armdpi, "$#%i,R%n,",
+ "CMP%C%S", armdpi, "$#%i,R%n,",
+ "CMN%C%S", armdpi, "$#%i,R%n,",
+ "ORR%C%S", armdpi, "$#%i,R%n,R%d",
+ "MOVW%C%S", armdpi, "$#%i,,R%d",
+ "BIC%C%S", armdpi, "$#%i,R%n,R%d",
+ "MVN%C%S", armdpi, "$#%i,,R%d",
+
+ "MUL%C%S", armdpi, "R%s,R%m,R%n",
+ "MULA%C%S", armdpi, "R%s,R%m,R%n,R%d",
+ "SWPW", armdpi, "R%s,(R%n),R%d",
+ "SWPB", armdpi, "R%s,(R%n),R%d",
+
+ "MOVW%C%p", armsdti,"R%d,#%i(R%n)",
+ "MOVB%C%p", armsdti,"R%d,#%i(R%n)",
+ "MOVW%C%p", armsdti,"#%i(R%n),R%d",
+ "MOVB%C%p", armsdti,"#%i(R%n),R%d",
+
+ "MOVW%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)",
+ "MOVB%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)",
+ "MOVW%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d",
+ "MOVB%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d",
+
+ "MOVM%C%P%a", armbdt, "R%n,[%r]",
+ "MOVM%C%P%a", armbdt, "[%r],R%n",
+
+ "B%C", armb, "%b",
+ "BL%C", armb, "%b",
+
+ "CDP%C", armco, "",
+ "CDP%C", armco, "",
+ "MCR%C", armco, "",
+ "MRC%C", armco, "",
+
+ "UNK", armunk, "",
+};
+
+static char *mode[] = { 0, "IA", "DB", "IB" };
+static char *pw[] = { "P", "PW", 0, "W" };
+static char *sw[] = { 0, "W", "S", "SW" };
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int j, k, m, n;
+
+ if(mnemonic)
+ format(0, i, mnemonic);
+ if(f == 0)
+ return;
+ if(mnemonic)
+ if(i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if(*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 'C': /* .CONDITION */
+ if(cond[i->cond])
+ bprint(i, ".%s", cond[i->cond]);
+ break;
+
+ case 'S': /* .STORE */
+ if(i->store)
+ bprint(i, ".S");
+ break;
+
+ case 'P': /* P & U bits for block move */
+ n = (i->w >>23) & 0x3;
+ if (mode[n])
+ bprint(i, ".%s", mode[n]);
+ break;
+
+ case 'D': /* ~U bit for single data xfer */
+ if((i->w & (1<<23)) == 0)
+ bprint(i, "-");
+ break;
+
+ case 'p': /* P & W bits for single data xfer*/
+ if (pw[i->store])
+ bprint(i, ".%s", pw[i->store]);
+ break;
+
+ case 'a': /* S & W bits for single data xfer*/
+ if (sw[i->store])
+ bprint(i, ".%s", sw[i->store]);
+ break;
+
+ case 's':
+ bprint(i, "%d", i->rs & 0xf);
+ break;
+
+ case 'm':
+ bprint(i, "%d", (i->w>>7) & 0x1f);
+ break;
+
+ case 'h':
+ bprint(i, "%s", shtype[(i->w>>5) & 0x3]);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->rn);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'i':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'b':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'r':
+ n = i->imm&0xffff;
+ j = 0;
+ k = 0;
+ while(n) {
+ m = j;
+ while(n&0x1) {
+ j++;
+ n >>= 1;
+ }
+ if(j != m) {
+ if(k)
+ bprint(i, ",");
+ if(j == m+1)
+ bprint(i, "R%d", m);
+ else
+ bprint(i, "R%d-R%d", m, j-1);
+ k = 1;
+ }
+ j++;
+ n >>= 1;
+ }
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+void
+das(ulong *x, int n)
+{
+ ulong pc;
+ Instr i;
+ char buf[128];
+
+ pc = (ulong)x;
+ while(n > 0) {
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+
+ if(decode(pc, &i) < 0)
+ sprint(buf, "???");
+ else
+ (*opcodes[i.op].f)(&opcodes[i.op], &i);
+
+ print("%.8lux %.8lux\t%s\n", pc, i.w, buf);
+ pc += 4;
+ n--;
+ }
+}
diff --git a/libinterp/das-mips.c b/libinterp/das-mips.c
new file mode 100644
index 00000000..4237320a
--- /dev/null
+++ b/libinterp/das-mips.c
@@ -0,0 +1,531 @@
+#include <lib9.h>
+
+/* mips native disassembler */
+
+typedef struct {
+ long addr; /* pc of instr */
+ uchar op; /* bits 31-26 */
+ uchar rs; /* bits 25-21 */
+ uchar rt; /* bits 20-16 */
+ uchar rd; /* bits 15-11 */
+ uchar sa; /* bits 10-6 */
+ uchar function; /* bits 5-0 */
+ long immediate; /* bits 15-0 */
+ ulong cofun; /* bits 24-0 */
+ ulong target; /* bits 25-0 */
+ long w0;
+ char *curr; /* current fill point */
+ char *end; /* end of buffer */
+ char *err;
+} Instr;
+
+typedef struct {
+ char *mnemonic;
+ char *mipsco;
+} Opcode;
+
+static char mipscoload[] = "r%t,%l";
+static char mipscoalui[] = "r%t,r%s,%i";
+static char mipscoalu3op[] = "r%d,r%s,r%t";
+static char mipscoboc[] = "r%s,r%t,%b";
+static char mipscoboc0[] = "r%s,%b";
+static char mipscorsrt[] = "r%s,r%t";
+static char mipscorsi[] = "r%s,%i";
+static char mipscoxxx[] = "%w";
+static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */
+static char mipscofp2[] = "f%a,f%d"; /* fd,fs */
+static char mipscofpc[] = "f%d,f%t"; /* fs,ft */
+
+static Opcode opcodes[64] = {
+ 0, 0,
+ 0, 0,
+ "j", "%j",
+ "jal", "%j",
+ "beq", mipscoboc,
+ "bne", mipscoboc,
+ "blez", mipscoboc0,
+ "bgtz", mipscoboc0,
+ "addi", mipscoalui,
+ "addiu", mipscoalui,
+ "slti", mipscoalui,
+ "sltiu", mipscoalui,
+ "andi", mipscoalui,
+ "ori", mipscoalui,
+ "xori", mipscoalui,
+ "lui", "r%t,%u",
+ "cop0", 0,
+ "cop1", 0,
+ "cop2", 0,
+ "cop3", 0,
+ "beql", mipscoboc,
+ "bnel", mipscoboc,
+ "blezl", mipscoboc0,
+ "bgtzl", mipscoboc0,
+ "instr18", mipscoxxx,
+ "instr19", mipscoxxx,
+ "instr1A", mipscoxxx,
+ "instr1B", mipscoxxx,
+ "instr1C", mipscoxxx,
+ "instr1D", mipscoxxx,
+ "instr1E", mipscoxxx,
+ "instr1F", mipscoxxx,
+ "lb", mipscoload,
+ "lh", mipscoload,
+ "lwl", mipscoload,
+ "lw", mipscoload,
+ "lbu", mipscoload,
+ "lhu", mipscoload,
+ "lwr", mipscoload,
+ "instr27", mipscoxxx,
+ "sb", mipscoload,
+ "sh", mipscoload,
+ "swl", mipscoload,
+ "sw", mipscoload,
+ "instr2C", mipscoxxx,
+ "instr2D", mipscoxxx,
+ "swr", mipscoload,
+ "cache", "",
+ "ll", mipscoload,
+ "lwc1", mipscoload,
+ "lwc2", mipscoload,
+ "lwc3", mipscoload,
+ "instr34", mipscoxxx,
+ "ld", mipscoload,
+ "ld", mipscoload,
+ "ld", mipscoload,
+ "sc", mipscoload,
+ "swc1", mipscoload,
+ "swc2", mipscoload,
+ "swc3", mipscoload,
+ "instr3C", mipscoxxx,
+ "sd", mipscoload,
+ "sd", mipscoload,
+ "sd", mipscoload,
+};
+
+static Opcode sopcodes[64] = {
+ "sll", "r%d,r%t,$%a",
+ "special01", mipscoxxx,
+ "srl", "r%d,r%t,$%a",
+ "sra", "r%d,r%t,$%a",
+ "sllv", "r%d,r%t,R%s",
+ "special05", mipscoxxx,
+ "srlv", "r%d,r%t,r%s",
+ "srav", "r%d,r%t,r%s",
+ "jr", "r%s",
+ "jalr", "r%d,r%s",
+ "special0A", mipscoxxx,
+ "special0B", mipscoxxx,
+ "syscall", "",
+ "break", "",
+ "special0E", mipscoxxx,
+ "sync", "",
+ "mfhi", "r%d",
+ "mthi", "r%s",
+ "mflo", "r%d",
+ "mtlo", "r%s",
+ "special14", mipscoxxx,
+ "special15", mipscoxxx,
+ "special16", mipscoxxx,
+ "special17", mipscoxxx,
+ "mult", mipscorsrt,
+ "multu", mipscorsrt,
+ "div", mipscorsrt,
+ "divu", mipscorsrt,
+ "special1C", mipscoxxx,
+ "special1D", mipscoxxx,
+ "special1E", mipscoxxx,
+ "special1F", mipscoxxx,
+ "add", mipscoalu3op,
+ "addu", mipscoalu3op,
+ "sub", mipscoalu3op,
+ "subu", mipscoalu3op,
+ "and", mipscoalu3op,
+ "or", mipscoalu3op,
+ "xor", mipscoalu3op,
+ "nor", mipscoalu3op,
+ "special28", mipscoxxx,
+ "special29", mipscoxxx,
+ "slt", mipscoalu3op,
+ "sltu", mipscoalu3op,
+ "special2C", mipscoxxx,
+ "special2D", mipscoxxx,
+ "special2E", mipscoxxx,
+ "special2F", mipscoxxx,
+ "tge", mipscorsrt,
+ "tgeu", mipscorsrt,
+ "tlt", mipscorsrt,
+ "tltu", mipscorsrt,
+ "teq", mipscorsrt,
+ "special35", mipscoxxx,
+ "tne", mipscorsrt,
+ "special37", mipscoxxx,
+ "special38", mipscoxxx,
+ "special39", mipscoxxx,
+ "special3A", mipscoxxx,
+ "special3B", mipscoxxx,
+ "special3C", mipscoxxx,
+ "special3D", mipscoxxx,
+ "special3E", mipscoxxx,
+ "special3F", mipscoxxx,
+};
+
+static Opcode ropcodes[32] = {
+ "bltz", mipscoboc0,
+ "bgez", mipscoboc0,
+ "bltzl", mipscoboc0,
+ "bgezl", mipscoboc0,
+ "regimm04", mipscoxxx,
+ "regimm05", mipscoxxx,
+ "regimm06", mipscoxxx,
+ "regimm07", mipscoxxx,
+ "tgei", mipscorsi,
+ "tgeiu", mipscorsi,
+ "tlti", mipscorsi,
+ "tltiu", mipscorsi,
+ "teqi", mipscorsi,
+ "regimm0D", mipscoxxx,
+ "tnei", mipscorsi,
+ "regimm0F", mipscoxxx,
+ "bltzal", mipscoboc0,
+ "bgezal", mipscoboc0,
+ "bltzall", mipscoboc0,
+ "bgezall", mipscoboc0,
+ "regimm14", mipscoxxx,
+ "regimm15", mipscoxxx,
+ "regimm16", mipscoxxx,
+ "regimm17", mipscoxxx,
+ "regimm18", mipscoxxx,
+ "regimm19", mipscoxxx,
+ "regimm1A", mipscoxxx,
+ "regimm1B", mipscoxxx,
+ "regimm1C", mipscoxxx,
+ "regimm1D", mipscoxxx,
+ "regimm1E", mipscoxxx,
+ "regimm1F", mipscoxxx,
+};
+
+static Opcode fopcodes[64] = {
+ "add.%f", mipscofp3,
+ "sub.%f", mipscofp3,
+ "mul.%f", mipscofp3,
+ "div.%f", mipscofp3,
+ "sqrt.%f", mipscofp2,
+ "abs.%f", mipscofp2,
+ "mov.%f", mipscofp2,
+ "neg.%f", mipscofp2,
+ "finstr08", mipscoxxx,
+ "finstr09", mipscoxxx,
+ "finstr0A", mipscoxxx,
+ "finstr0B", mipscoxxx,
+ "round.w.%f", mipscofp2,
+ "trunc.w%f", mipscofp2,
+ "ceil.w%f", mipscofp2,
+ "floor.w%f", mipscofp2,
+ "finstr10", mipscoxxx,
+ "finstr11", mipscoxxx,
+ "finstr12", mipscoxxx,
+ "finstr13", mipscoxxx,
+ "finstr14", mipscoxxx,
+ "finstr15", mipscoxxx,
+ "finstr16", mipscoxxx,
+ "finstr17", mipscoxxx,
+ "finstr18", mipscoxxx,
+ "finstr19", mipscoxxx,
+ "finstr1A", mipscoxxx,
+ "finstr1B", mipscoxxx,
+ "finstr1C", mipscoxxx,
+ "finstr1D", mipscoxxx,
+ "finstr1E", mipscoxxx,
+ "finstr1F", mipscoxxx,
+ "cvt.s.%f", mipscofp2,
+ "cvt.d.%f", mipscofp2,
+ "cvt.e.%f", mipscofp2,
+ "cvt.q.%f", mipscofp2,
+ "cvt.w.%f", mipscofp2,
+ "finstr25", mipscoxxx,
+ "finstr26", mipscoxxx,
+ "finstr27", mipscoxxx,
+ "finstr28", mipscoxxx,
+ "finstr29", mipscoxxx,
+ "finstr2A", mipscoxxx,
+ "finstr2B", mipscoxxx,
+ "finstr2C", mipscoxxx,
+ "finstr2D", mipscoxxx,
+ "finstr2E", mipscoxxx,
+ "finstr2F", mipscoxxx,
+ "c.f.%f", mipscofpc,
+ "c.un.%f", mipscofpc,
+ "c.eq.%f", mipscofpc,
+ "c.ueq.%f", mipscofpc,
+ "c.olt.%f", mipscofpc,
+ "c.ult.%f", mipscofpc,
+ "c.ole.%f", mipscofpc,
+ "c.ule.%f", mipscofpc,
+ "c.sf.%f", mipscofpc,
+ "c.ngle.%f", mipscofpc,
+ "c.seq.%f", mipscofpc,
+ "c.ngl.%f", mipscofpc,
+ "c.lt.%f", mipscofpc,
+ "c.nge.%f", mipscofpc,
+ "c.le.%f", mipscofpc,
+ "c.ngt.%f", mipscofpc,
+};
+
+static char fsub[16] = {
+ 's', 'd', 'e', 'q', 'w', '?', '?', '?',
+ '?', '?', '?', '?', '?', '?', '?', '?'
+};
+
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if (*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 's':
+ bprint(i, "%d", i->rs);
+ break;
+
+ case 't':
+ bprint(i, "%d", i->rt);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->sa);
+ break;
+
+ case 'l':
+ bprint(i, "%d(r%d)", i->immediate, i->rs);
+ break;
+
+ case 'u':
+ case 'i':
+ bprint(i, "$%d", i->immediate);
+ break;
+
+ case 'j':
+ bprint(i, "0x%lux", (i->target<<2)|(i->addr & 0xF0000000));
+ break;
+
+ case 'b':
+ bprint(i, "0x%lux", (i->immediate<<2)+i->addr+4);
+ break;
+
+ case 'c':
+ bprint(i, "0x%lux", i->cofun);
+ break;
+
+ case 'w':
+ bprint(i, "[0x%lux]", i->w0);
+ break;
+
+ case 'f':
+ *i->curr++ = fsub[i->rs & 0x0F];
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+static void
+copz(int cop, Instr *i)
+{
+ char *f, *m, buf[16];
+
+ m = buf;
+ f = "%t,%d";
+ switch (i->rs) {
+
+ case 0:
+ sprint(buf, "mfc%d", cop);
+ break;
+
+ case 2:
+ sprint(buf, "cfc%d", cop);
+ break;
+
+ case 4:
+ sprint(buf, "mtc%d", cop);
+ break;
+
+ case 6:
+ sprint(buf, "ctc%d", cop);
+ break;
+
+ case 8:
+ f = "%b";
+ switch (i->rt) {
+
+ case 0:
+ sprint(buf, "bc%df", cop);
+ break;
+
+ case 1:
+ sprint(buf, "bc%dt", cop);
+ break;
+
+ case 2:
+ sprint(buf, "bc%dfl", cop);
+ break;
+
+ case 3:
+ sprint(buf, "bc%dtl", cop);
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ f = mipscoxxx;
+ break;
+ }
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ if (i->rs & 0x10)
+ f = "function %c";
+ else
+ f = mipscoxxx;
+ break;
+ }
+ format(m, i, f);
+}
+
+static void
+cop0(Instr *i)
+{
+ char *m = 0;
+
+ if (i->rs >= 0x10) {
+ switch (i->cofun) {
+
+ case 1:
+ m = "tlbr";
+ break;
+
+ case 2:
+ m = "tlbwi";
+ break;
+
+ case 6:
+ m = "tlbwr";
+ break;
+
+ case 8:
+ m = "tlbp";
+ break;
+
+ case 16:
+ m = "rfe";
+ break;
+
+ case 32:
+ m = "eret";
+ break;
+ }
+ if (m) {
+ format(m, i, 0);
+ if (i->curr < i->end)
+ *i->curr++ = 0;
+ return;
+ }
+ }
+ copz(0, i);
+}
+
+void
+das(ulong *pc)
+{
+ Instr i;
+ char buf[100];
+ Opcode *o;
+ uchar op;
+ ulong w;
+
+ w = *pc;
+
+ i.addr = (ulong)pc;
+ i.op = (w >> 26) & 0x3F;
+ i.rs = (w >> 21) & 0x1F;
+ i.rt = (w >> 16) & 0x1F;
+ i.rd = (w >> 11) & 0x1F;
+ i.sa = (w >> 6) & 0x1F;
+ i.function = w & 0x3F;
+ i.immediate = w & 0x0000FFFF;
+ if(i.immediate & 0x8000)
+ i.immediate |= ~0x0000FFFF;
+ i.cofun = w & 0x01FFFFFF;
+ i.target = w & 0x03FFFFFF;
+ i.w0 = w;
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+
+ i.curr += sprint(i.curr, " %.8p %.8lux", pc, w);
+
+ o = opcodes;
+ op = i.op;
+ switch (i.op) {
+
+ case 0x00: /* SPECIAL */
+ o = sopcodes;
+ op = i.function;
+ break;
+
+ case 0x01: /* REGIMM */
+ o = ropcodes;
+ op = i.rt;
+ break;
+
+ case 0x10: /* COP0 */
+ cop0(&i);
+ break;
+
+ case 0x11: /* COP1 */
+ if (i.rs & 0x10) {
+ o = fopcodes;
+ op = i.function;
+ break;
+ }
+ /*FALLTHROUGH*/
+ case 0x12: /* COP2 */
+ case 0x13: /* COP3 */
+ copz(i.op-0x10, &i);
+ break;
+ }
+ format(o[op].mnemonic, &i, o[op].mipsco);
+ *i.curr++ = '\n';
+ *i.curr = 0;
+ print("%s", buf);
+}
diff --git a/libinterp/das-power.c b/libinterp/das-power.c
new file mode 100644
index 00000000..a3a1799a
--- /dev/null
+++ b/libinterp/das-power.c
@@ -0,0 +1,961 @@
+#include <lib9.h>
+
+/*
+ * disassemble PowerPC opcodes in Plan9 format
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+/*
+ * ibm conventions for these: bit 0 is top bit
+ * from table 10-1
+ */
+typedef struct {
+ uchar aa; /* bit 30 */
+ uchar crba; /* bits 11-15 */
+ uchar crbb; /* bits 16-20 */
+ long bd; /* bits 16-29 */
+ uchar crfd; /* bits 6-8 */
+ uchar crfs; /* bits 11-13 */
+ uchar bi; /* bits 11-15 */
+ uchar bo; /* bits 6-10 */
+ uchar crbd; /* bits 6-10 */
+ union {
+ short d; /* bits 16-31 */
+ short simm;
+ ushort uimm;
+ };
+ uchar fm; /* bits 7-14 */
+ uchar fra; /* bits 11-15 */
+ uchar frb; /* bits 16-20 */
+ uchar frc; /* bits 21-25 */
+ uchar frs; /* bits 6-10 */
+ uchar frd; /* bits 6-10 */
+ uchar crm; /* bits 12-19 */
+ long li; /* bits 6-29 || b'00' */
+ uchar lk; /* bit 31 */
+ uchar mb; /* bits 21-25 */
+ uchar me; /* bits 26-30 */
+ uchar nb; /* bits 16-20 */
+ uchar op; /* bits 0-5 */
+ uchar oe; /* bit 21 */
+ uchar ra; /* bits 11-15 */
+ uchar rb; /* bits 16-20 */
+ uchar rc; /* bit 31 */
+ union {
+ uchar rs; /* bits 6-10 */
+ uchar rd;
+ };
+ uchar sh; /* bits 16-20 */
+ ushort spr; /* bits 11-20 */
+ uchar to; /* bits 6-10 */
+ uchar imm; /* bits 16-19 */
+ ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */
+ long immediate;
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ short target;
+ char *curr; /* current fill level in output buffer */
+ char *end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char *err; /* errmsg */
+} Instr;
+
+#define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
+#define IB(v,b) IBF((v),(b),(b))
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong *pc, Instr *i)
+{
+ ulong w;
+
+ w = *pc;
+ i->aa = IB(w, 30);
+ i->crba = IBF(w, 11, 15);
+ i->crbb = IBF(w, 16, 20);
+ i->bd = IBF(w, 16, 29)<<2;
+ if(i->bd & 0x8000)
+ i->bd |= ~0L<<16;
+ i->crfd = IBF(w, 6, 8);
+ i->crfs = IBF(w, 11, 13);
+ i->bi = IBF(w, 11, 15);
+ i->bo = IBF(w, 6, 10);
+ i->crbd = IBF(w, 6, 10);
+ i->uimm = IBF(w, 16, 31); /* also d, simm */
+ i->fm = IBF(w, 7, 14);
+ i->fra = IBF(w, 11, 15);
+ i->frb = IBF(w, 16, 20);
+ i->frc = IBF(w, 21, 25);
+ i->frs = IBF(w, 6, 10);
+ i->frd = IBF(w, 6, 10);
+ i->crm = IBF(w, 12, 19);
+ i->li = IBF(w, 6, 29)<<2;
+ if(IB(w, 6))
+ i->li |= ~0<<25;
+ i->lk = IB(w, 31);
+ i->mb = IBF(w, 21, 25);
+ i->me = IBF(w, 26, 30);
+ i->nb = IBF(w, 16, 20);
+ i->op = IBF(w, 0, 5);
+ i->oe = IB(w, 21);
+ i->ra = IBF(w, 11, 15);
+ i->rb = IBF(w, 16, 20);
+ i->rc = IB(w, 31);
+ i->rs = IBF(w, 6, 10); /* also rd */
+ i->sh = IBF(w, 16, 20);
+ i->spr = IBF(w, 11, 20);
+ i->to = IBF(w, 6, 10);
+ i->imm = IBF(w, 16, 19);
+ i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */
+ i->immediate = i->simm;
+ if(i->op == 15)
+ i->immediate <<= 16;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = (ulong)pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong *pc, Instr *i)
+{
+ Instr x;
+
+ if(decode(pc, i) < 0)
+ return -1;
+ /*
+ * combine ADDIS/ORI (CAU/ORIL) into MOVW
+ */
+ if (i->op == 15 && i->ra==0) {
+ if(decode(pc+1, &x) < 0)
+ return -1;
+ if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
+ i->immediate |= (x.immediate & 0xFFFF);
+ i->w1 = x.w0;
+ i->target = x.rd;
+ i->size++;
+ return 1;
+ }
+ }
+ return 1;
+}
+
+static void
+pglobal(Instr *i, long off, char *reg)
+{
+ bprint(i, "%lux%s", off, reg);
+}
+
+static void
+address(Instr *i)
+{
+ if(i->simm < 0)
+ bprint(i, "-%lx(R%d)", -i->simm, i->ra);
+ else
+ bprint(i, "%lux(R%d)", i->immediate, i->ra);
+}
+
+static char *tcrbits[] = {"LT", "GT", "EQ", "VS"};
+static char *fcrbits[] = {"GE", "LE", "NE", "VC"};
+
+typedef struct Opcode Opcode;
+
+struct Opcode {
+ uchar op;
+ ushort xo;
+ ushort xomask;
+ char *mnemonic;
+ void (*f)(Opcode *, Instr *);
+ char *ken;
+ int flags;
+};
+
+static void format(char *, Instr *, char *);
+
+static void
+branch(Opcode *o, Instr *i)
+{
+ char buf[8];
+ int bo, bi;
+
+ bo = i->bo & ~1; /* ignore prediction bit */
+ if(bo==4 || bo==12 || bo==20) { /* simple forms */
+ if(bo != 20) {
+ bi = i->bi&3;
+ sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
+ format(buf, i, 0);
+ bprint(i, "\t");
+ if(i->bi > 4)
+ bprint(i, "CR(%d),", i->bi/4);
+ } else
+ format("BR%L\t", i, 0);
+ if(i->op == 16)
+ format(0, i, "%J");
+ else if(i->op == 19 && i->xo == 528)
+ format(0, i, "(CTR)");
+ else if(i->op == 19 && i->xo == 16)
+ format(0, i, "(LR)");
+ } else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+addi(Opcode *o, Instr *i)
+{
+ if (i->op==14 && i->ra == 0)
+ format("MOVW", i, "%i,R%d");
+ else if(i->op==14 && i->simm < 0) {
+ bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else if(i->ra == i->rd) {
+ format(o->mnemonic, i, "%i");
+ bprint(i, ",R%d", i->rd);
+ } else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+addis(Opcode *o, Instr *i)
+{
+ long v;
+
+ v = i->immediate;
+ if (i->op==15 && i->ra == 0)
+ bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
+ else if(i->op==15 && v < 0) {
+ bprint(i, "SUB\t$%d,R%d", -v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else {
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t$%ld,R%d", v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ }
+}
+
+static void
+andi(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "%I,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+gencc(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+gen(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, o->ken);
+ if (i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+ldx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b),R%d");
+ else
+ format(o->mnemonic, i, "(R%b+R%a),R%d");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+stx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "R%d,(R%b)");
+ else
+ format(o->mnemonic, i, "R%d,(R%b+R%a)");
+ if(i->rc && i->xo != 150)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+fldx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b),F%d");
+ else
+ format(o->mnemonic, i, "(R%b+R%a),F%d");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+fstx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "F%d,(R%b)");
+ else
+ format(o->mnemonic, i, "F%d,(R%b+R%a)");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+dcb(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b)");
+ else
+ format(o->mnemonic, i, "(R%b+R%a)");
+ if(i->rd)
+ bprint(i, " [illegal Rd]");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+lw(Opcode *o, Instr *i, char r)
+{
+ bprint(i, "%s\t", o->mnemonic);
+ address(i);
+ bprint(i, ",%c%d", r, i->rd);
+}
+
+static void
+load(Opcode *o, Instr *i)
+{
+ lw(o, i, 'R');
+}
+
+static void
+fload(Opcode *o, Instr *i)
+{
+ lw(o, i, 'F');
+}
+
+static void
+sw(Opcode *o, Instr *i, char r)
+{
+ char *m;
+
+ m = o->mnemonic;
+ if (r == 'F')
+ format(m, i, "F%d,%l");
+ else
+ format(m, i, o->ken);
+}
+
+static void
+store(Opcode *o, Instr *i)
+{
+ sw(o, i, 'R');
+}
+
+static void
+fstore(Opcode *o, Instr *i)
+{
+ sw(o, i, 'F');
+}
+
+static void
+shifti(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "$%k,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+shift(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "R%b,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+add(Opcode *o, Instr *i)
+{
+ if (i->rd == i->ra)
+ format(o->mnemonic, i, "R%b,R%d");
+ else if (i->rd == i->rb)
+ format(o->mnemonic, i, "R%a,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+sub(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t");
+ if(i->op == 31) {
+ bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */
+ if(i->rd != i->rb)
+ bprint(i, ",R%d", i->rd);
+ } else
+ bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
+}
+
+static void
+div(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ if(i->op == 31)
+ bprint(i, "\tR%d,R%d", i->rb, i->ra);
+ else
+ bprint(i, "\t$%d,R%d", i->simm, i->ra);
+ if(i->ra != i->rd)
+ bprint(i, ",R%d", i->rd);
+}
+
+static void
+and(Opcode *o, Instr *i)
+{
+ if (i->op == 31) {
+ /* Rb,Rs,Ra */
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "R%b,R%a");
+ else if (i->ra == i->rb)
+ format(o->mnemonic, i, "R%s,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+ } else {
+ /* imm,Rs,Ra */
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "%I,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+ }
+}
+
+static void
+or(Opcode *o, Instr *i)
+{
+ if (i->op == 31) {
+ /* Rb,Rs,Ra */
+ if (i->rs == 0 && i->ra == 0 && i->rb == 0)
+ format("NOP", i, 0);
+ else if (i->rs == i->rb)
+ format("MOVW", i, "R%b,R%a");
+ else
+ and(o, i);
+ } else
+ and(o, i);
+}
+
+static void
+shifted(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
+ if (i->rs == i->ra)
+ bprint(i, "R%d", i->ra);
+ else
+ bprint(i, "R%d,R%d", i->rs, i->ra);
+}
+
+static void
+neg(Opcode *o, Instr *i)
+{
+ if (i->rd == i->ra)
+ format(o->mnemonic, i, "R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static char ir2[] = "R%a,R%d"; /* reverse of IBM order */
+static char ir3[] = "R%b,R%a,R%d";
+static char ir3r[] = "R%a,R%b,R%d";
+static char il3[] = "R%b,R%s,R%a";
+static char il2u[] = "%I,R%s,R%a";
+static char il3s[] = "$%k,R%s,R%a";
+static char il2[] = "R%s,R%a";
+static char icmp3[] = "R%a,R%b,%D";
+static char cr3op[] = "%b,%a,%d";
+static char ir2i[] = "%i,R%a,R%d";
+static char fp2[] = "F%b,F%d";
+static char fp3[] = "F%b,F%a,F%d";
+static char fp3c[] = "F%c,F%a,F%d";
+static char fp4[] = "F%a,F%c,F%b,F%d";
+static char fpcmp[] = "F%a,F%b,%D";
+static char ldop[] = "%l,R%d";
+static char stop[] = "R%d,%l";
+static char fldop[] = "%l,F%d";
+static char fstop[] = "F%d,%l";
+static char rlim[] = "R%b,R%s,$%z,R%a";
+static char rlimi[] = "$%k,R%s,$%z,R%a";
+
+#define OEM IBF(~0,22,30)
+#define FP4 IBF(~0,26,30)
+#define ALL (~0)
+/*
+notes:
+ 10-26: crfD = rD>>2; rD&3 mbz
+ also, L bit (bit 10) mbz or selects 64-bit operands
+*/
+
+static Opcode opcodes[] = {
+ {31, 266, OEM, "ADD%V%C", add, ir3},
+ {31, 10, OEM, "ADDC%V%C", add, ir3},
+ {31, 138, OEM, "ADDE%V%C", add, ir3},
+ {14, 0, 0, "ADD", addi, ir2i},
+ {12, 0, 0, "ADDC", addi, ir2i},
+ {13, 0, 0, "ADDCCC", addi, ir2i},
+ {15, 0, 0, "ADD", addis, 0},
+ {31, 234, OEM, "ADDME%V%C", gencc, ir2},
+ {31, 202, OEM, "ADDZE%V%C", gencc, ir2},
+
+ {31, 28, ALL, "AND%C", and, il3},
+ {31, 60, ALL, "ANDN%C", and, il3},
+ {28, 0, 0, "ANDCC", andi, il2u},
+ {29, 0, 0, "ANDCC", shifted, 0},
+
+ {18, 0, 0, "B%L", gencc, "%j"},
+ {16, 0, 0, "BC%L", branch, "%d,%a,%J"},
+ {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"},
+ {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"},
+
+ {31, 0, ALL, "CMP", 0, icmp3},
+ {11, 0, 0, "CMP", 0, "R%a,%i,%D"},
+ {31, 32, ALL, "CMPU", 0, icmp3},
+ {10, 0, 0, "CMPU", 0, "R%a,%I,%D"},
+
+ {31, 26, ALL, "CNTLZ%C", gencc, ir2},
+
+ {19, 257, ALL, "CRAND", gen, cr3op},
+ {19, 129, ALL, "CRANDN", gen, cr3op},
+ {19, 289, ALL, "CREQV", gen, cr3op},
+ {19, 225, ALL, "CRNAND", gen, cr3op},
+ {19, 33, ALL, "CRNOR", gen, cr3op},
+ {19, 449, ALL, "CROR", gen, cr3op},
+ {19, 417, ALL, "CRORN", gen, cr3op},
+ {19, 193, ALL, "CRXOR", gen, cr3op},
+
+ {31, 86, ALL, "DCBF", dcb, 0},
+ {31, 470, ALL, "DCBI", dcb, 0},
+ {31, 54, ALL, "DCBST", dcb, 0},
+ {31, 278, ALL, "DCBT", dcb, 0},
+ {31, 246, ALL, "DCBTST", dcb, 0},
+ {31, 1014, ALL, "DCBZ", dcb, 0},
+
+ {31, 491, OEM, "DIVW%V%C", div, ir3},
+ {31, 459, OEM, "DIVWU%V%C", div, ir3},
+
+ {31, 310, ALL, "ECIWX", ldx, 0},
+ {31, 438, ALL, "ECOWX", stx, 0},
+ {31, 854, ALL, "EIEIO", gen, 0},
+
+ {31, 284, ALL, "EQV%C", gencc, il3},
+
+ {31, 954, ALL, "EXTSB%C", gencc, il2},
+ {31, 922, ALL, "EXTSH%C", gencc, il2},
+
+ {63, 264, ALL, "FABS%C", gencc, fp2},
+ {63, 21, ALL, "FADD%C", gencc, fp3},
+ {59, 21, ALL, "FADDS%C", gencc, fp3},
+ {63, 32, ALL, "FCMPO", gen, fpcmp},
+ {63, 0, ALL, "FCMPU", gen, fpcmp},
+ {63, 14, ALL, "FCTIW%C", gencc, fp2},
+ {63, 15, ALL, "FCTIWZ%C", gencc, fp2},
+ {63, 18, ALL, "FDIV%C", gencc, fp3},
+ {59, 18, ALL, "FDIVS%C", gencc, fp3},
+ {63, 29, FP4, "FMADD%C", gencc, fp4},
+ {59, 29, FP4, "FMADDS%C", gencc, fp4},
+ {63, 72, ALL, "FMOVD%C", gencc, fp2},
+ {63, 28, FP4, "FMSUB%C", gencc, fp4},
+ {59, 28, FP4, "FMSUBS%C", gencc, fp4},
+ {63, 25, FP4, "FMUL%C", gencc, fp3c},
+ {59, 25, FP4, "FMULS%C", gencc, fp3c},
+ {63, 136, ALL, "FNABS%C", gencc, fp2},
+ {63, 40, ALL, "FNEG%C", gencc, fp2},
+ {63, 31, FP4, "FNMADD%C", gencc, fp4},
+ {59, 31, FP4, "FNMADDS%C", gencc, fp4},
+ {63, 30, FP4, "FNMSUB%C", gencc, fp4},
+ {59, 30, FP4, "FNMSUBS%C", gencc, fp4},
+ {63, 12, ALL, "FRSP%C", gencc, fp2},
+ {63, 20, FP4, "FSUB%C", gencc, fp3},
+ {59, 20, FP4, "FSUBS%C", gencc, fp3},
+
+ {31, 982, ALL, "ICBI", dcb, 0},
+ {19, 150, ALL, "ISYNC", gen, 0},
+
+ {34, 0, 0, "MOVBZ", load, ldop},
+ {35, 0, 0, "MOVBZU", load, ldop},
+ {31, 119, ALL, "MOVBZU", ldx, 0},
+ {31, 87, ALL, "MOVBZ", ldx, 0},
+ {50, 0, 0, "FMOVD", fload, fldop},
+ {51, 0, 0, "FMOVDU", fload, fldop},
+ {31, 631, ALL, "FMOVDU", fldx, 0},
+ {31, 599, ALL, "FMOVD", fldx, 0},
+ {48, 0, 0, "FMOVS", load, fldop},
+ {49, 0, 0, "FMOVSU", load, fldop},
+ {31, 567, ALL, "FMOVSU", fldx, 0},
+ {31, 535, ALL, "FMOVS", fldx, 0},
+ {42, 0, 0, "MOVH", load, ldop},
+ {43, 0, 0, "MOVHU", load, ldop},
+ {31, 375, ALL, "MOVHU", ldx, 0},
+ {31, 343, ALL, "MOVH", ldx, 0},
+ {31, 790, ALL, "MOVHBR", ldx, 0},
+ {40, 0, 0, "MOVHZ", load, ldop},
+ {41, 0, 0, "MOVHZU", load, ldop},
+ {31, 311, ALL, "MOVHZU", ldx, 0},
+ {31, 279, ALL, "MOVHZ", ldx, 0},
+ {46, 0, 0, "MOVMW", load, ldop},
+ {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"},
+ {31, 533, ALL, "LSW", ldx, 0},
+ {31, 20, ALL, "LWAR", ldx, 0},
+ {31, 534, ALL, "MOVWBR", ldx, 0},
+ {32, 0, 0, "MOVW", load, ldop},
+ {33, 0, 0, "MOVWU", load, ldop},
+ {31, 55, ALL, "MOVWU", ldx, 0},
+ {31, 23, ALL, "MOVW", ldx, 0},
+
+ {19, 0, ALL, "MOVFL", gen, "%S,%D"},
+ {63, 64, ALL, "MOVCRFS", gen, "%S,%D"},
+ {31, 512, ALL, "MOVW", gen, "XER,%D"},
+ {31, 19, ALL, "MOVW", gen, "CR,R%d"},
+
+ {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */
+ {31, 83, ALL, "MOVW", gen, "MSR,R%d"},
+ {31, 339, ALL, "MOVW", gen, "%P,R%d"},
+ {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"},
+ {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"},
+ {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"},
+ {63, 70, ALL, "MTFSB0%C", gencc, "%D"},
+ {63, 38, ALL, "MTFSB1%C", gencc, "%D"},
+ {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */
+ {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"},
+ {31, 146, ALL, "MOVW", gen, "R%s,MSR"},
+ {31, 467, ALL, "MOVW", gen, "R%s,%P"},
+ {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"},
+ {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"},
+
+ {31, 235, OEM, "MULLW%V%C", gencc, ir3},
+ {7, 0, 0, "MULLW", div, "%i,R%a,R%d"},
+
+ {31, 476, ALL, "NAND%C", gencc, il3},
+ {31, 104, OEM, "NEG%V%C", neg, ir2},
+ {31, 124, ALL, "NOR%C", gencc, il3},
+ {31, 444, ALL, "OR%C", or, il3},
+ {31, 412, ALL, "ORN%C", or, il3},
+ {24, 0, 0, "OR", and, "%I,R%d,R%a"},
+ {25, 0, 0, "OR", shifted, 0},
+
+ {19, 50, ALL, "RFI", gen, 0},
+
+ {20, 0, 0, "RLWMI%C", gencc, rlimi},
+ {21, 0, 0, "RLWNM%C", gencc, rlimi},
+ {23, 0, 0, "RLWNM%C", gencc, rlim},
+
+ {17, 1, ALL, "SYSCALL", gen, 0},
+
+ {31, 24, ALL, "SLW%C", shift, il3},
+
+ {31, 792, ALL, "SRAW%C", shift, il3},
+ {31, 824, ALL, "SRAW%C", shifti, il3s},
+
+ {31, 536, ALL, "SRW%C", shift, il3},
+
+ {38, 0, 0, "MOVB", store, stop},
+ {39, 0, 0, "MOVBU", store, stop},
+ {31, 247, ALL, "MOVBU", stx, 0},
+ {31, 215, ALL, "MOVB", stx, 0},
+ {54, 0, 0, "FMOVD", fstore, fstop},
+ {55, 0, 0, "FMOVDU", fstore, fstop},
+ {31, 759, ALL, "FMOVDU", fstx, 0},
+ {31, 727, ALL, "FMOVD", fstx, 0},
+ {52, 0, 0, "FMOVS", fstore, fstop},
+ {53, 0, 0, "FMOVSU", fstore, fstop},
+ {31, 695, ALL, "FMOVSU", fstx, 0},
+ {31, 663, ALL, "FMOVS", fstx, 0},
+ {44, 0, 0, "MOVH", store, stop},
+ {31, 918, ALL, "MOVHBR", stx, 0},
+ {45, 0, 0, "MOVHU", store, stop},
+ {31, 439, ALL, "MOVHU", stx, 0},
+ {31, 407, ALL, "MOVH", stx, 0},
+ {47, 0, 0, "MOVMW", store, stop},
+ {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"},
+ {31, 661, ALL, "STSW", stx, 0},
+ {36, 0, 0, "MOVW", store, stop},
+ {31, 662, ALL, "MOVWBR", stx, 0},
+ {31, 150, ALL, "STWCCC", stx, 0},
+ {37, 0, 0, "MOVWU", store, stop},
+ {31, 183, ALL, "MOVWU", stx, 0},
+ {31, 151, ALL, "MOVW", stx, 0},
+
+ {31, 40, OEM, "SUB%V%C", sub, ir3},
+ {31, 8, OEM, "SUBC%V%C", sub, ir3},
+ {31, 136, OEM, "SUBE%V%C", sub, ir3},
+ {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"},
+ {31, 232, OEM, "SUBME%V%C", sub, ir2},
+ {31, 200, OEM, "SUBZE%V%C", sub, ir2},
+
+ {31, 598, ALL, "SYNC", gen, 0},
+ {31, 306, ALL, "TLBIE", gen, "R%b"},
+ {31, 1010, ALL, "TLBLI", gen, "R%b"},
+ {31, 978, ALL, "TLBLD", gen, "R%b"},
+ {31, 4, ALL, "TW", gen, "%d,R%a,R%b"},
+ {3, 0, 0, "TW", gen, "%d,R%a,%i"},
+
+ {31, 316, ALL, "XOR", and, il3},
+ {26, 0, 0, "XOR", and, il2u},
+ {27, 0, 0, "XOR", shifted, 0},
+
+ {0},
+};
+
+typedef struct Spr Spr;
+struct Spr {
+ int n;
+ char *name;
+};
+
+static Spr sprname[] = {
+ {0, "MQ"},
+ {1, "XER"},
+ {268, "TBL"},
+ {269, "TBU"},
+ {8, "LR"},
+ {9, "CTR"},
+ {528, "IBAT0U"},
+ {529, "IBAT0L"},
+ {530, "IBAT1U"},
+ {531, "IBAT1L"},
+ {532, "IBAT2U"},
+ {533, "IBAT2L"},
+ {534, "IBAT3U"},
+ {535, "IBAT3L"},
+ {536, "DBAT0U"},
+ {537, "DBAT0L"},
+ {538, "DBAT1U"},
+ {539, "DBAT1L"},
+ {540, "DBAT2U"},
+ {541, "DBAT2L"},
+ {542, "DBAT3U"},
+ {543, "DBAT3L"},
+ {25, "SDR1"},
+ {19, "DAR"},
+ {272, "SPRG0"},
+ {273, "SPRG1"},
+ {274, "SPRG2"},
+ {275, "SPRG3"},
+ {18, "DSISR"},
+ {26, "SRR0"},
+ {27, "SRR1"},
+ {284, "TBLW"},
+ {285, "TBUW"},
+ {22, "DEC"},
+ {282, "EAR"},
+ {1008, "HID0"},
+ {1009, "HID1"},
+ {976, "DMISS"},
+ {977, "DCMP"},
+ {978, "HASH1"},
+ {979, "HASH2"},
+ {980, "IMISS"},
+ {981, "ICMP"},
+ {982, "RPA"},
+ {1010, "IABR"},
+ {0,0},
+};
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int n, s;
+ ulong mask;
+
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (mnemonic)
+ bprint(i, "\t");
+ for ( ; *f; f++) {
+ if (*f != '%') {
+ bprint(i, "%c", *f);
+ continue;
+ }
+ switch (*++f) {
+ case 'V':
+ if(i->oe)
+ bprint(i, "V");
+ break;
+
+ case 'C':
+ if(i->rc)
+ bprint(i, "CC");
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->ra);
+ break;
+
+ case 'b':
+ bprint(i, "%d", i->rb);
+ break;
+
+ case 'c':
+ bprint(i, "%d", i->frc);
+ break;
+
+ case 'd':
+ case 's':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'S':
+ if(i->ra & 3)
+ bprint(i, "CR(INVAL:%d)", i->ra);
+ else if(i->op == 63)
+ bprint(i, "FPSCR(%d)", i->crfs);
+ else
+ bprint(i, "CR(%d)", i->crfs);
+ break;
+
+ case 'D':
+ if(i->rd & 3)
+ bprint(i, "CR(INVAL:%d)", i->rd);
+ else if(i->op == 63)
+ bprint(i, "FPSCR(%d)", i->crfd);
+ else
+ bprint(i, "CR(%d)", i->crfd);
+ break;
+
+ case 'l':
+ if(i->simm < 0)
+ bprint(i, "-%lx(R%d)", -i->simm, i->ra);
+ else
+ bprint(i, "%lx(R%d)", i->simm, i->ra);
+ break;
+
+ case 'i':
+ bprint(i, "$%ld", i->simm);
+ break;
+
+ case 'I':
+ bprint(i, "$%lx", i->uimm);
+ break;
+
+ case 'w':
+ bprint(i, "[%lux]", i->w0);
+ break;
+
+ case 'P':
+ n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
+ for(s=0; sprname[s].name; s++)
+ if(sprname[s].n == n)
+ break;
+ if(sprname[s].name) {
+ if(n < 10)
+ bprint(i, sprname[s].name);
+ else
+ bprint(i, "SPR(%s)", sprname[s].name);
+ } else
+ bprint(i, "SPR(%d)", n);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */
+ break;
+
+ case 'm':
+ bprint(i, "%lx", i->crm);
+ break;
+
+ case 'M':
+ bprint(i, "%lx", i->fm);
+ break;
+
+ case 'z':
+ if(i->mb <= i->me)
+ mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
+ else
+ mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
+ bprint(i, "%lux", mask);
+ break;
+
+ case 'k':
+ bprint(i, "%d", i->sh);
+ break;
+
+ case 'K':
+ bprint(i, "$%x", i->imm);
+ break;
+
+ case 'L':
+ if(i->lk)
+ bprint(i, "L");
+ break;
+
+ case 'j':
+ if(i->aa)
+ pglobal(i, i->li, "(ABS)");
+ else
+ pglobal(i, i->addr+i->li, "(REL)");
+ break;
+
+ case 'J':
+ if(i->aa)
+ pglobal(i, i->bd, "(ABS)");
+ else
+ pglobal(i, i->addr+i->bd, "(REL)");
+ break;
+
+ case '\0':
+ bprint(i, "%%");
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+int
+das(ulong *pc)
+{
+ Instr i;
+ Opcode *o;
+ char buf[100];
+ int r;
+
+ memset(&i, 0, sizeof(i));
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+ r = mkinstr(pc, &i);
+ i.curr += sprint(i.curr, " %.8lux %.8lux ", (ulong)pc, i.w0);
+ if(r >= 0){
+ if(i.size == 2)
+ i.curr += sprint(i.curr, "%.8lux ", i.w1);
+ for(o = opcodes; o->mnemonic != 0; o++)
+ if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
+ if (o->f)
+ (*o->f)(o, &i);
+ else
+ format(o->mnemonic, &i, o->ken);
+ print("%s\n", buf);
+ return i.size;
+ }
+ }
+ strcpy(i.curr, "ILLEGAL");
+ print("%s\n", buf);
+ return i.size;
+}
diff --git a/libinterp/das-s800.c b/libinterp/das-s800.c
new file mode 100644
index 00000000..a96cc23a
--- /dev/null
+++ b/libinterp/das-s800.c
@@ -0,0 +1,457 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+/* s800 disassembler. */
+/* does not handle stuff that won't be generated */
+
+typedef struct instr Instr;
+
+struct instr
+{
+ ulong value; /* bits 31-00 */
+ uchar op; /* bits 31-26 */
+ uchar subop; /* bits 11-05 */
+ uchar sysop; /* bits 12-05 */
+ uchar reg0; /* bits 25-21 */
+ uchar reg1; /* bits 20-16 */
+ uchar reg2; /* bits 4-0 */
+ uchar space; /* bits 15-14 */
+ uchar indexed; /* bit 13 */
+ uchar cond; /* bits 15-13 */
+ uchar sr; /* bits 13,15,14 */
+ uchar ftype; /* bits 12-9 */
+ uchar simm; /* bit 12 */
+ uchar store; /* bit 9 */
+ uchar size; /* bits 8-6 */
+ uchar mod; /* bit 5 */
+ uchar shz; /* bit 9-5 */
+ long imm21; /* bits 20-00 */
+ short simm14; /* bits 13-01, sign 00 */
+ short simm11; /* bits 10-01, sign 00 */
+ short simm5; /* bits 4-1, sign 0 */
+ short off; /* bits 13-02, sign 00 */
+ char csimm5; /* bits 20-17, sign 16 */
+ char *curr; /* current fill level in output buffer */
+ char *end; /* end of buffer */
+};
+
+typedef struct opdec Opdec;
+
+struct opdec
+{
+ char *mnem;
+ void (*func)(Instr *, char *);
+};
+
+static char ill[] = "ILL";
+static char sizes[] = "BHWXXXXX";
+
+static char *conds[8] =
+{
+ "never",
+ "equal",
+ "less",
+ "leq",
+ "lessu",
+ "lequ",
+ "sv",
+ "odd",
+};
+
+static char *fconds[8] =
+{
+ "F",
+ "==",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "!=",
+ "T",
+};
+
+static void das_nil(Instr *, char *);
+static void das_sys(Instr *, char *);
+static void das_arith(Instr *, char *);
+static void das_ldwx(Instr *, char *);
+static void das_ld(Instr *, char *);
+static void das_ldil(Instr *, char *);
+static void das_ldo(Instr *, char *);
+static void das_st(Instr *, char *);
+static void das_fldst(Instr *, char *);
+static void das_fltc(Instr *, char *);
+static void das_combt(Instr *, char *);
+static void das_ibt(Instr *, char *);
+static void das_combf(Instr *, char *);
+static void das_ibf(Instr *, char *);
+static void das_extrs(Instr *, char *);
+static void das_be(Instr *, char *);
+static void das_bx(Instr *, char *);
+
+Opdec dastab[1 << 6] =
+{
+ {ill, das_sys}, /* 0x00 */
+ {ill, das_nil}, /* 0x01 */
+ {ill, das_arith}, /* 0x02 */
+ {ill, das_ldwx}, /* 0x03 */
+ {ill, das_nil}, /* 0x04 */
+ {ill, das_nil}, /* 0x05 */
+ {ill, das_nil}, /* 0x06 */
+ {ill, das_nil}, /* 0x07 */
+ {ill, das_ldil}, /* 0x08 */
+ {ill, das_nil}, /* 0x09 */
+ {ill, das_nil}, /* 0x0A */
+ {ill, das_fldst}, /* 0x0B */
+ {ill, das_fltc}, /* 0x0C */
+ {ill, das_ldo}, /* 0x0D */
+ {ill, das_nil}, /* 0x0E */
+ {ill, das_nil}, /* 0x0F */
+
+ {"LDB", das_ld}, /* 0x10 */
+ {"LDH", das_ld}, /* 0x11 */
+ {"LDW", das_ld}, /* 0x12 */
+ {ill, das_nil}, /* 0x13 */
+ {ill, das_nil}, /* 0x14 */
+ {ill, das_nil}, /* 0x15 */
+ {ill, das_nil}, /* 0x16 */
+ {ill, das_nil}, /* 0x17 */
+ {"STB", das_st}, /* 0x18 */
+ {"STH", das_st}, /* 0x19 */
+ {"STW", das_st}, /* 0x1A */
+ {ill, das_nil}, /* 0x1B */
+ {ill, das_nil}, /* 0x1C */
+ {ill, das_nil}, /* 0x1D */
+ {ill, das_nil}, /* 0x1E */
+ {ill, das_nil}, /* 0x1F */
+
+ {ill, das_combt}, /* 0x20 */
+ {"COM", das_ibt}, /* 0x21 */
+ {ill, das_combf}, /* 0x22 */
+ {"COM", das_ibf}, /* 0x23 */
+ {ill, das_nil}, /* 0x24 */
+ {ill, das_nil}, /* 0x25 */
+ {ill, das_nil}, /* 0x26 */
+ {ill, das_nil}, /* 0x27 */
+ {ill, das_nil}, /* 0x28 */
+ {"ADD", das_ibt}, /* 0x29 */
+ {ill, das_nil}, /* 0x2A */
+ {"ADD", das_ibf}, /* 0x2B */
+ {ill, das_nil}, /* 0x2C */
+ {ill, das_nil}, /* 0x2D */
+ {ill, das_nil}, /* 0x2E */
+ {ill, das_nil}, /* 0x2F */
+
+ {ill, das_nil}, /* 0x30 */
+ {ill, das_nil}, /* 0x31 */
+ {ill, das_nil}, /* 0x32 */
+ {ill, das_nil}, /* 0x33 */
+ {ill, das_extrs}, /* 0x34 */
+ {ill, das_nil}, /* 0x35 */
+ {ill, das_nil}, /* 0x36 */
+ {ill, das_nil}, /* 0x37 */
+ {"BE", das_be}, /* 0x38 */
+ {"BLE", das_be}, /* 0x39 */
+ {ill, das_bx}, /* 0x3A */
+ {ill, das_nil}, /* 0x3B */
+ {ill, das_nil}, /* 0x3C */
+ {ill, das_nil}, /* 0x3D */
+ {ill, das_nil}, /* 0x3E */
+ {ill, das_nil}, /* 0x3F */
+};
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+decode(ulong *pc, Instr *i)
+{
+ ulong w;
+ int t;
+
+ w = *pc;
+
+ i->value = w;
+ i->op = (w >> 26) & 0x3F;
+ i->subop = (w >> 5) & 0x7F;
+ i->sysop = (w >> 5) & 0xFF;
+ i->reg0 = (w >> 21) & 0x1F;
+ i->reg1 = (w >> 16) & 0x1F;
+ i->reg2 = w & 0x1F;
+ i->space = (w >> 14) & 0x03;
+ i->indexed = (w >> 13) & 0x01;
+ i->cond = (w >> 13) & 0x07;
+ i->sr = (i->cond >> 1) | ((i->cond & 1) << 2);
+ i->ftype = (w >> 9) & 0xF;
+ i->simm = (w >> 12) & 0x01;
+ i->store = (w >> 9) & 0x01;
+ i->size = (w >> 6) & 0x07;
+ i->mod = (w >> 5) & 0x01;
+ i->shz = (w >> 5) & 0x1F;
+ i->imm21 = w & 0x01FFFFF;
+ i->simm14 = (w >> 1) & 0x1FFF;
+ i->simm11 = (w >> 1) & 0x03FF;
+ i->simm5 = (w >> 1) & 0x0F;
+ i->off = ((w >> 3) & 0x3FF) | ((w & (1 << 2)) << 8);
+ i->csimm5 = (w >> 17) & 0x0F;
+ if(w & 1) {
+ i->simm14 |= ~((1 << 13) - 1);
+ i->simm11 |= ~((1 << 10) - 1);
+ i->simm5 |= ~((1 << 4) - 1);
+ i->off |= ~((1 << 10) - 1);
+ }
+ if(w & (1 << 16))
+ i->csimm5 |= ~((1 << 4) - 1);
+}
+
+static void
+das_ill(Instr *i)
+{
+ das_nil(i, ill);
+}
+
+static void
+das_nil(Instr *i, char *m)
+{
+ bprint(i, "%s\t%lx", m, i->value);
+}
+
+static void
+das_sys(Instr *i, char *m)
+{
+ switch(i->sysop) {
+ case 0x85:
+ bprint(i, "LDSID\t(sr%d,r%d),r%d", i->sr, i->reg0, i->reg2);
+ break;
+ case 0xC1:
+ bprint(i, "MTSP\tr%d,sr%d", i->reg1, i->sr);
+ break;
+ default:
+ das_ill(i);
+ }
+}
+
+static void
+das_arith(Instr *i, char *m)
+{
+ switch(i->subop) {
+ case 0x10:
+ m = "AND";
+ break;
+ case 0x12:
+ if (i->reg1 + i->reg0 + i->reg2 == 0) {
+ bprint(i, "NOP");
+ return;
+ }
+ m = "OR";
+ break;
+ case 0x14:
+ m = "XOR";
+ break;
+ case 0x20:
+ m = "SUB";
+ break;
+ case 0x30:
+ m = "ADD";
+ break;
+ case 0x32:
+ m = "SH1ADD";
+ break;
+ case 0x34:
+ m = "SH2ADD";
+ break;
+ default:
+ das_ill(i);
+ return;
+ }
+
+ bprint(i, "%s\tr%d,r%d,r%d", m, i->reg1, i->reg0, i->reg2);
+}
+
+static void
+das_ldwx(Instr *i, char *m)
+{
+ bprint(i, "LD%cX\tr%d(r%d),r%d", sizes[i->size], i->reg0, i->reg1, i->reg2);
+}
+
+static void
+das_ld(Instr *i, char *m)
+{
+ bprint(i, "%s\t%d(r%d),r%d", m, i->simm14, i->reg0, i->reg1);
+}
+
+static ulong
+unfrig17(ulong v)
+{
+ ulong r;
+
+ r = ((v >> 3) & 0x3FF) |
+ ((v & (1 << 2)) << 8) |
+ ((v & (0x1F << 16)) >> 5);
+ if (v & 1)
+ r |= ~((1 << 16) - 1);
+ return r << 2;
+}
+
+static ulong
+unfrig21(ulong v)
+{
+ return (((v & 1) << 20) |
+ ((v & (0x7FF << 1)) << 8) |
+ ((v >> 12) & 3) |
+ ((v & (3 << 14)) >> 7) |
+ ((v & (0x1F << 16)) >> 14)) << 11;
+}
+
+static void
+das_ldil(Instr *i, char *m)
+{
+ bprint(i, "LDIL\tL%%0x%lx,r%d", unfrig21(i->imm21), i->reg0);
+}
+
+static void
+das_ldo(Instr *i, char *m)
+{
+ bprint(i, "LDO\t%d(r%d),r%d", i->simm14, i->reg0, i->reg1);
+}
+
+static void
+das_st(Instr *i, char *m)
+{
+ bprint(i, "%s\tr%d,%d(r%d)", m, i->reg1, i->simm14, i->reg0);
+}
+
+static void
+das_fldst(Instr *i, char *m)
+{
+ if (i->simm) {
+ if (i->store)
+ bprint(i, "FSTDS\tfr%d,%d(r%d)", i->reg2, i->csimm5, i->reg0);
+ else
+ bprint(i, "FLDDS\t%d(r%d),fr%d", i->reg0, i->csimm5, i->reg2);
+ }
+ else {
+ if (i->store)
+ bprint(i, "FSTDX\tfr%d,r%d(r%d)", i->reg2, i->reg1, i->reg0);
+ else
+ bprint(i, "FLDDX\tr%d(r%d),fr%d", i->reg0, i->reg1, i->reg2);
+ }
+}
+
+static void
+das_fltc(Instr *i, char *m)
+{
+ char *o;
+
+ switch (i->ftype) {
+ case 2:
+ bprint(i, "FTEST");
+ break;
+ case 6:
+ bprint(i, "FCMP\tfr%d,%s,fr%d", i->reg0, fconds[i->reg2 >> 2], i->reg1);
+ break;
+ case 7:
+ switch (i->cond) {
+ case 0:
+ o = "ADD";
+ break;
+ case 1:
+ o = "SUB";
+ break;
+ case 2:
+ o = "MUL";
+ break;
+ case 3:
+ o = "DIV";
+ break;
+ default:
+ das_ill(i);
+ return;
+ }
+ bprint(i, "F%s\tfr%d,fr%d,fr%d", o, i->reg0, i->reg1, i->reg2);
+ break;
+ default:
+ das_ill(i);
+ }
+}
+
+static void
+das_combt(Instr *i, char *m)
+{
+ bprint(i, "COMBT,%s\tr%d,r%d,%d", conds[i->cond], i->reg1, i->reg0, i->off);
+}
+
+static void
+das_ibt(Instr *i, char *m)
+{
+ bprint(i, "%sIBT,%s\t%d,r%d,%d", m, conds[i->cond], i->csimm5, i->reg0, i->off);
+}
+
+static void
+das_combf(Instr *i, char *m)
+{
+ bprint(i, "COMBF,%s\tr%d,r%d,%d", conds[i->cond], i->reg1, i->reg0, i->off);
+}
+
+static void
+das_ibf(Instr *i, char *m)
+{
+ bprint(i, "%sIBF,%s\t%d,r%d,%d", m, conds[i->cond], i->csimm5, i->reg0, i->off);
+}
+
+static void
+das_extrs(Instr *i, char *m)
+{
+ bprint(i, "EXTRS\tr%d,%d,%d,r%d", i->reg0, i->shz, 32 - i->reg2, i->reg1);
+}
+
+static void
+das_be(Instr *i, char *m)
+{
+ bprint(i, "%s\t%d(sr%d,r%d)", m, unfrig17(i->value), i->sr, i->reg0);
+}
+
+static void
+das_bx(Instr *i, char *m)
+{
+ switch(i->cond) {
+ case 0:
+ bprint(i, "BL\t%d,r%d", unfrig17(i->value), i->reg0);
+ break;
+ case 6:
+ bprint(i, "BV\tr%d(r%d)", i->reg1, i->reg0);
+ break;
+ default:
+ das_ill(i);
+ }
+}
+
+static int
+inst(ulong *pc)
+{
+ Instr instr;
+ static char buf[128];
+
+ decode(pc, &instr);
+ instr.curr = buf;
+ instr.end = buf + sizeof(buf) - 1;
+ (*dastab[instr.op].func)(&instr, dastab[instr.op].mnem);
+ if (cflag > 5)
+ print("\t%.8lux %.8lux %s\n", pc, *pc, buf);
+ else
+ print("\t%.8lux %s\n", pc, buf);
+}
+
+void
+das(ulong *x, int n)
+{
+ while (--n >= 0)
+ inst(x++);
+}
diff --git a/libinterp/das-sparc.c b/libinterp/das-sparc.c
new file mode 100644
index 00000000..fb5280a4
--- /dev/null
+++ b/libinterp/das-sparc.c
@@ -0,0 +1,833 @@
+#include <lib9.h>
+
+ /* Sparc disassembler and related functions */
+
+typedef struct instr Instr;
+
+struct opcode
+{
+ char *mnemonic;
+ void (*f)(Instr*, char*);
+ int flag;
+};
+
+static char FRAMENAME[] = ".frame";
+
+
+struct instr
+{
+ uchar op; /* bits 31-30 */
+ uchar rd; /* bits 29-25 */
+ uchar op2; /* bits 24-22 */
+ uchar a; /* bit 29 */
+ uchar cond; /* bits 28-25 */
+ uchar op3; /* bits 24-19 */
+ uchar rs1; /* bits 18-14 */
+ uchar i; /* bit 13 */
+ uchar asi; /* bits 12-05 */
+ uchar rs2; /* bits 04-00 */
+ short simm13; /* bits 12-00, signed */
+ ushort opf; /* bits 13-05 */
+ ulong immdisp22; /* bits 21-00 */
+ ulong simmdisp22; /* bits 21-00, signed */
+ ulong disp30; /* bits 30-00 */
+ ulong imm32; /* SETHI+ADD constant */
+ int target; /* SETHI+ADD dest reg */
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ char* curr; /* current fill level in output buffer */
+ char* end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char* err; /* errmsg */
+};
+
+static int dascase;
+
+static int mkinstr(ulong*, Instr*);
+static void bra1(Instr*, char*, char*[]);
+static void bra(Instr*, char*);
+static void fbra(Instr*, char*);
+static void cbra(Instr*, char*);
+static void unimp(Instr*, char*);
+static void fpop(Instr*, char*);
+static void shift(Instr*, char*);
+static void sethi(Instr*, char*);
+static void load(Instr*, char*);
+static void loada(Instr*, char*);
+static void store(Instr*, char*);
+static void storea(Instr*, char*);
+static void add(Instr*, char*);
+static void cmp(Instr*, char*);
+static void wr(Instr*, char*);
+static void jmpl(Instr*, char*);
+static void rd(Instr*, char*);
+static void loadf(Instr*, char*);
+static void storef(Instr*, char*);
+static void loadc(Instr*, char*);
+static void loadcsr(Instr*, char*);
+static void trap(Instr*, char*);
+
+static struct opcode sparcop0[8] = {
+ /* [0] */ "UNIMP", unimp, 0, /* page 137 */
+ 0, 0, 0,
+ /* [2] */ "B", bra, 0, /* page 119 */
+ 0, 0, 0,
+ /* [4] */ "SETHI", sethi, 0, /* page 104 */
+ 0, 0, 0,
+ /* [6] */ "FB", fbra, 0, /* page 121 */
+ /* [7] */ "CB", cbra, 0, /* page 123 */
+};
+
+static struct opcode sparcop2[64] = {
+ /* [0x00] */ "ADD", add, 0, /* page 108 */
+ /* [0x01] */ "AND", add, 0, /* page 106 */
+ /* [0x02] */ "OR", add, 0,
+ /* [0x03] */ "XOR", add, 0,
+ /* [0x04] */ "SUB", add, 0, /* page 110 */
+ /* [0x05] */ "ANDN", add, 0,
+ /* [0x06] */ "ORN", add, 0,
+ /* [0x07] */ "XORN", add, 0,
+ /* [0x08] */ "ADDX", add, 0,
+ 0, 0, 0,
+ /* [0x0A] */ "UMUL", add, 0, /* page 113 */
+ /* [0x0B] */ "SMUL", add, 0,
+ /* [0x0C] */ "SUBX", add, 0,
+ 0, 0, 0,
+ /* [0x0E] */ "UDIV", add, 0, /* page 115 */
+ /* [0x0F] */ "SDIV", add, 0,
+ /* [0x10] */ "ADDCC", add, 0,
+ /* [0x11] */ "ANDCC", add, 0,
+ /* [0x12] */ "ORCC", add, 0,
+ /* [0x13] */ "XORCC", add, 0,
+ /* [0x14] */ "SUBCC", cmp, 0,
+ /* [0x15] */ "ANDNCC", add, 0,
+ /* [0x16] */ "ORNCC", add, 0,
+ /* [0x17] */ "XORNCC", add, 0,
+ /* [0x18] */ "ADDXCC", add, 0,
+ 0, 0, 0,
+ /* [0x1A] */ "UMULCC", add, 0,
+ /* [0x1B] */ "SMULCC", add, 0,
+ /* [0x1C] */ "SUBXCC", add, 0,
+ 0, 0, 0,
+ /* [0x1E] */ "UDIVCC", add, 0,
+ /* [0x1F] */ "SDIVCC", add, 0,
+ /* [0x20] */ "TADD", add, 0, /* page 109 */
+ /* [0x21] */ "TSUB", add, 0, /* page 111 */
+ /* [0x22] */ "TADDCCTV", add, 0,
+ /* [0x23] */ "TSUBCCTV", add, 0,
+ /* [0x24] */ "MULSCC", add, 0, /* page 112 */
+ /* [0x25] */ "SLL", shift, 0, /* page 107 */
+ /* [0x26] */ "SRL", shift, 0,
+ /* [0x27] */ "SRA", shift, 0,
+ /* [0x28] */ "rdy", rd, 0, /* page 131 */
+ /* [0x29] */ "rdpsr", rd, 0,
+ /* [0x2A] */ "rdwim", rd, 0,
+ /* [0x2B] */ "rdtbr", rd, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x30] */ "wry", wr, 0, /* page 133 */
+ /* [0x31] */ "wrpsr", wr, 0,
+ /* [0x32] */ "wrwim", wr, 0,
+ /* [0x33] */ "wrtbr", wr, 0,
+ /* [0x34] */ "FPOP", fpop, 0, /* page 140 */
+ /* [0x35] */ "FPOP", fpop, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x38] */ "JMPL", jmpl, 0, /* page 126 */
+ /* [0x39] */ "RETT", add, 0, /* page 127 */
+ /* [0x3A] */ "T", trap, 0, /* page 129 */
+ /* [0x3B] */ "flush", add, 0, /* page 138 */
+ /* [0x3C] */ "SAVE", add, 0, /* page 117 */
+ /* [0x3D] */ "RESTORE", add, 0,
+};
+
+static struct opcode sparcop3[64]={
+ /* [0x00] */ "ld", load, 0,
+ /* [0x01] */ "ldub", load, 0,
+ /* [0x02] */ "lduh", load, 0,
+ /* [0x03] */ "ldd", load, 0,
+ /* [0x04] */ "st", store, 0,
+ /* [0x05] */ "stb", store, 0, /* page 95 */
+ /* [0x06] */ "sth", store, 0,
+ /* [0x07] */ "std", store, 0,
+ 0, 0, 0,
+ /* [0x09] */ "ldsb", load, 0, /* page 90 */
+ /* [0x0A] */ "ldsh", load, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x0D] */ "ldstub", store, 0, /* page 101 */
+ 0, 0, 0,
+ /* [0x0F] */ "swap", load, 0, /* page 102 */
+ /* [0x10] */ "lda", loada, 0,
+ /* [0x11] */ "lduba", loada, 0,
+ /* [0x12] */ "lduha", loada, 0,
+ /* [0x13] */ "ldda", loada, 0,
+ /* [0x14] */ "sta", storea, 0,
+ /* [0x15] */ "stba", storea, 0,
+ /* [0x16] */ "stha", storea, 0,
+ /* [0x17] */ "stda", storea, 0,
+ 0, 0, 0,
+ /* [0x19] */ "ldsba", loada, 0,
+ /* [0x1A] */ "ldsha", loada, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x1D] */ "ldstuba", storea, 0,
+ 0, 0, 0,
+ /* [0x1F] */ "swapa", loada, 0,
+ /* [0x20] */ "ldf", loadf, 0, /* page 92 */
+ /* [0x21] */ "ldfsr", loadf, 0,
+ 0, 0, 0,
+ /* [0x23] */ "lddf", loadf, 0,
+ /* [0x24] */ "stf", storef, 0, /* page 97 */
+ /* [0x25] */ "stfsr", storef, 0,
+ /* [0x26] */ "stdfq", storef, 0,
+ /* [0x27] */ "stdf", storef, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x30] */ "ldc", loadc, 0, /* page 94 */
+ /* [0x31] */ "ldcsr", loadcsr,0,
+ 0, 0, 0,
+ /* [0x33] */ "lddc", loadc, 0,
+ /* [0x34] */ "stc", loadc, 0, /* page 99 */
+ /* [0x35] */ "stcsr", loadcsr,0,
+ /* [0x36] */ "stdcq", loadcsr,0,
+ /* [0x37] */ "stdc", loadc, 0,
+};
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong *pc, Instr *i)
+{
+ ulong w;
+
+ w = *pc;
+
+ i->op = (w >> 30) & 0x03;
+ i->rd = (w >> 25) & 0x1F;
+ i->op2 = (w >> 22) & 0x07;
+ i->a = (w >> 29) & 0x01;
+ i->cond = (w >> 25) & 0x0F;
+ i->op3 = (w >> 19) & 0x3F;
+ i->rs1 = (w >> 14) & 0x1F;
+ i->i = (w >> 13) & 0x01;
+ i->asi = (w >> 5) & 0xFF;
+ i->rs2 = (w >> 0) & 0x1F;
+ i->simm13 = (w >> 0) & 0x1FFF;
+ if(i->simm13 & (1<<12))
+ i->simm13 |= ~((1<<13)-1);
+ i->opf = (w >> 5) & 0x1FF;
+ i->immdisp22 = (w >> 0) & 0x3FFFFF;
+ i->simmdisp22 = i->immdisp22;
+ if(i->simmdisp22 & (1<<21))
+ i->simmdisp22 |= ~((1<<22)-1);
+ i->disp30 = (w >> 0) & 0x3FFFFFFF;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = (ulong)pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong *pc, Instr *i)
+{
+ Instr xi;
+
+ if (decode(pc, i) < 0)
+ return -1;
+ if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */
+ if(decode(pc+1, &xi) < 0)
+ return -1;
+ if(xi.op == 2 && xi.op3 == 0) /* ADD */
+ if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */
+ i->imm32 = xi.simm13 + (i->immdisp22<<10);
+ i->target = xi.rd;
+ i->w1 = xi.w0;
+ i->size++;
+ return 1;
+ }
+ }
+ if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */
+ if (decode(pc+1, &xi) < 0)
+ return -1;
+ if(i->op==2 && i->opf==1) /* FMOVS */
+ if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
+ i->w1 = xi.w0;
+ i->size++;
+ }
+ }
+ return 1;
+}
+
+static int
+inst(ulong *pc)
+{
+ long disp;
+ Instr instr;
+ static char buf[128];
+ void (*f)(Instr*, char*);
+
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+sizeof(buf)-1;
+ if(mkinstr(pc, &instr) < 0)
+ return 4;
+ switch(instr.op){
+ case 0:
+ f = sparcop0[instr.op2].f;
+ if(f)
+ (*f)(&instr, sparcop0[instr.op2].mnemonic);
+ else
+ bprint(&instr, "unknown 0x%lux", instr.w0);
+ break;
+
+ case 1:
+ disp = instr.disp30;
+ disp = (disp<<2)>>2;
+ bprint(&instr, "CALL\t0x%lux", pc+disp);
+ if (!dascase)
+ bprint(&instr, "(SB)");
+ break;
+
+ case 2:
+ f = sparcop2[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop2[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown 0x%lux", instr.w0);
+ break;
+
+ case 3:
+ f = sparcop3[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop3[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown 0x%lux", instr.w0);
+ break;
+ }
+ if (instr.err) {
+ if (instr.curr != buf)
+ bprint(&instr, "\t\t;");
+ bprint(&instr, instr.err);
+ }
+ print("\t%.8lux %s\n", (ulong)pc, buf);
+
+ return instr.size;
+}
+
+void
+das(ulong *pc, int n)
+{
+ ulong *e;
+
+ e = pc + n;
+ while(pc < e)
+ pc += inst(pc);
+}
+
+static void
+address(Instr *i)
+{
+ bprint(i, "0x%lux(R%d)", i->simm13, i->rs1);
+}
+
+static void
+unimp(Instr *i, char *m)
+{
+ bprint(i, "%s", m);
+}
+
+static char *bratab[16] = { /* page 91 */
+ /* [0x0] */ "N",
+ /* [0x1] */ "E",
+ /* [0x2] */ "LE",
+ /* [0x3] */ "L",
+ /* [0x4] */ "LEU",
+ /* [0x5] */ "CS",
+ /* [0x6] */ "NEG",
+ /* [0x7] */ "VS",
+ /* [0x8] */ "A",
+ /* [0x9] */ "NE",
+ /* [0xA] */ "G",
+ /* [0xB] */ "GE",
+ /* [0xC] */ "GU",
+ /* [0xD] */ "CC",
+ /* [0xE] */ "POS",
+ /* [0xF] */ "VC",
+};
+
+static char *fbratab[16] = { /* page 91 */
+ /* [0x0] */ "N",
+ /* [0x1] */ "NE",
+ /* [0x2] */ "LG",
+ /* [0x3] */ "UL",
+ /* [0x4] */ "L",
+ /* [0x5] */ "UG",
+ /* [0x6] */ "G",
+ /* [0x7] */ "U",
+ /* [0x8] */ "A",
+ /* [0x9] */ "E",
+ /* [0xA] */ "UE",
+ /* [0xB] */ "GE",
+ /* [0xC] */ "UGE",
+ /* [0xD] */ "LE",
+ /* [0xE] */ "ULE",
+ /* [0xF] */ "O",
+};
+
+static char *cbratab[16] = { /* page 91 */
+ /* [0x0] */ "N",
+ /* [0x1] */ "123",
+ /* [0x2] */ "12",
+ /* [0x3] */ "13",
+ /* [0x4] */ "1",
+ /* [0x5] */ "23",
+ /* [0x6] */ "2",
+ /* [0x7] */ "3",
+ /* [0x8] */ "A",
+ /* [0x9] */ "0",
+ /* [0xA] */ "03",
+ /* [0xB] */ "02",
+ /* [0xC] */ "023",
+ /* [0xD] */ "01",
+ /* [0xE] */ "013",
+ /* [0xF] */ "012",
+};
+
+static void
+bra1(Instr *i, char *m, char *tab[])
+{
+ long imm;
+
+ imm = i->simmdisp22;
+ if(i->a)
+ bprint(i, "%s%s.%c\t", m, tab[i->cond], 'A'+dascase);
+ else
+ bprint(i, "%s%s\t", m, tab[i->cond]);
+ bprint(i, "0x%lux", i->addr+4*imm);
+ if (!dascase)
+ bprint(i, "(SB)");
+}
+
+static void
+bra(Instr *i, char *m) /* page 91 */
+{
+ bra1(i, m, bratab);
+}
+
+static void
+fbra(Instr *i, char *m) /* page 93 */
+{
+ bra1(i, m, fbratab);
+}
+
+static void
+cbra(Instr *i, char *m) /* page 95 */
+{
+ bra1(i, m, cbratab);
+}
+
+static void
+trap(Instr *i, char *m) /* page 101 */
+{
+ if(i->i == 0)
+ bprint(i, "%s%s\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
+ else
+ bprint(i, "%s%s\t$0x%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
+}
+
+static void
+sethi(Instr *i, char *m) /* page 89 */
+{
+ ulong imm;
+
+ imm = i->immdisp22<<10;
+ if(dascase){
+ bprint(i, "%s\t0x%lux, R%d", m, imm, i->rd);
+ return;
+ }
+ if(imm==0 && i->rd==0){
+ bprint(i, "NOP");
+ return;
+ }
+ if(i->target < 0){
+ bprint(i, "MOVW\t$0x%lux, R%d", imm, i->rd);
+ return;
+ }
+ bprint(i, "MOVW\t$0x%lux, R%d", i->imm32, i->target);
+}
+
+static char ldtab[] = {
+ 'W',
+ 'B',
+ 'H',
+ 'D',
+};
+
+static char*
+moveinstr(int op3, char *m)
+{
+ char *s;
+ int c;
+ static char buf[8];
+
+ if(!dascase){
+ /* batshit cases */
+ if(op3 == 0xF || op3 == 0x1F)
+ return "SWAP";
+ if(op3 == 0xD || op3 == 0x1D)
+ return "TAS"; /* really LDSTUB */
+ c = ldtab[op3&3];
+ s = "";
+ if((op3&11)==1 || (op3&11)==2)
+ s="U";
+ sprint(buf, "MOV%c%s", c, s);
+ return buf;
+ }
+ return m;
+}
+
+static void
+load(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+}
+
+static void
+loada(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
+ else
+ bprint(i, "unknown ld asi 0x%lux", i->w0);
+}
+
+static void
+store(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d)",
+ m, i->rd, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\tR%d, ", m, i->rd);
+ address(i);
+ }
+}
+
+static void
+storea(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
+ else
+ bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
+}
+
+static void
+shift(Instr *i, char *m) /* page 88 */
+{
+ if(i->i == 0){
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%s\tR%d, R%d", m, i->rs2, i->rs1);
+ else
+ if(dascase)
+ bprint(i, "%s\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
+ else
+ bprint(i, "%s\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%s\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
+ else
+ bprint(i, "%s\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
+ else
+ if(dascase)
+ bprint(i, "%s\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
+ else
+ bprint(i, "%s\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
+ }
+}
+
+static void
+add(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(dascase)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */
+ bprint(i, "MOVW\tR%d", i->rs2);
+ else
+ bprint(i, "%s\tR%d, R%d", m, i->rs2, i->rs1);
+ }else{
+ if(dascase)
+ bprint(i, "%s\tR%d, $0x%lux", m, i->rs1, i->simm13);
+ else
+ if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */
+ bprint(i, "MOVW\t$0x%lux", i->simm13);
+ else if(i->op3==0 && i->rd && i->rs1==2){
+ /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
+ bprint(i, "MOVW\t$");
+ address(i);
+ } else
+ bprint(i, "%s\t$0x%lux, R%d", m, i->simm13, i->rs1);
+ }
+ if(i->rs1 != i->rd)
+ bprint(i, ", R%d", i->rd);
+}
+
+static void
+cmp(Instr *i, char *m)
+{
+ if(dascase || i->rd){
+ add(i, m);
+ return;
+ }
+ if(i->i == 0)
+ bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
+ else
+ bprint(i, "CMP\tR%d, $0x%lux", i->rs1, i->simm13);
+}
+
+static char *regtab[4] =
+{
+ "Y",
+ "PSR",
+ "WIM",
+ "TBR",
+};
+
+static void
+wr(Instr *i, char *m) /* page 82 */
+{
+ if(dascase){
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%s\tR%d, $0x%lux", m, i->rs1, i->simm13);
+ }else{
+ if(i->i && i->simm13==0)
+ bprint(i, "MOVW\tR%d", i->rs1);
+ else if(i->i == 0)
+ bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
+ else
+ bprint(i, "wr\t$0x%lux, R%d", i->simm13, i->rs1);
+ }
+ bprint(i, ", %s", regtab[i->op3&3]);
+}
+
+static void
+rd(Instr *i, char *m) /* page 103 */
+{
+ if(i->rs1==15 && i->rd==0){
+ m = "stbar";
+ if(!dascase)
+ m = "STBAR";
+ bprint(i, "%s", m);
+ }else{
+ if(!dascase)
+ m = "MOVW";
+ bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
+ }
+}
+
+static void
+jmpl(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(i->rd == 15)
+ bprint(i, "CALL\t(R%d+R%d)", i->rs2, i->rs1);
+ else
+ bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
+ bprint(i, "RETURN");
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+ }
+}
+
+static void
+loadf(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x20)
+ m = "FMOVF";
+ else if(i->op3 == 0x21)
+ m = "MOVW";
+ }
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ }
+ if(i->op3 == 0x21)
+ bprint(i, ", FSR");
+ else
+ bprint(i, ", R%d", i->rd);
+}
+
+static
+void storef(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x25 || i->op3 == 0x26)
+ m = "MOVW";
+ else if(i->op3 == 0x24)
+ m = "FMOVF";
+ }
+ bprint(i, "%s\t", m);
+ if(i->op3 == 0x25)
+ bprint(i, "FSR, ");
+ else if(i->op3 == 0x26)
+ bprint(i, "FQ, ");
+ else
+ bprint(i, "R%d, ", i->rd);
+ if(i->i == 0)
+ bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
+ else
+ address(i);
+}
+
+static
+void loadc(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", C%d", i->rd);
+ }
+}
+
+static
+void loadcsr(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", CSR");
+ }
+}
+
+static struct
+{
+ int opf;
+ char *name;
+} fptab1[] = { /* ignores rs1 */
+ 0xC4, "FITOS", /* page 109 */
+ 0xC8, "FITOD",
+ 0xCC, "FITOX",
+
+ 0xD1, "FSTOI", /* page 110 */
+ 0xD2, "FDTOI",
+ 0xD3, "FXTOI",
+
+ 0xC9, "FSTOD", /* page 111 */
+ 0xCD, "FSTOX",
+ 0xC6, "FDTOS",
+ 0xCE, "FDTOX",
+ 0xC7, "FXTOS",
+ 0xCB, "FXTOD",
+
+ 0x01, "FMOVS", /* page 112 */
+ 0x05, "FNEGS",
+ 0x09, "FABSS",
+
+ 0x29, "FSQRTS", /* page 113 */
+ 0x2A, "FSQRTD",
+ 0x2B, "FSQRTX",
+
+ 0, 0,
+};
+
+static struct{
+ int opf;
+ char *name;
+} fptab2[] = { /* uses rs1 */
+
+ 0x41, "FADDS", /* page 114 */
+ 0x42, "FADDD",
+ 0x43, "FADDX",
+ 0x45, "FSUBS",
+ 0x46, "FSUBD",
+ 0x47, "FSUBX",
+
+ 0x49, "FMULS", /* page 115 */
+ 0x4A, "FMULD",
+ 0x4B, "FMULX",
+ 0x4D, "FDIVS",
+ 0x4E, "FDIVD",
+ 0x4F, "FDIVX",
+
+ 0x51, "FCMPS", /* page 116 */
+ 0x52, "FCMPD",
+ 0x53, "FCMPX",
+ 0x55, "FCMPES",
+ 0x56, "FCMPED",
+ 0x57, "FCMPEX",
+
+ 0, 0
+};
+
+static void
+fpop(Instr *i, char *m) /* page 108-116 */
+{
+ int j;
+
+ if(dascase==0 && i->size==2){
+ bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab1[j].name; j++)
+ if(fptab1[j].opf == i->opf){
+ bprint(i, "%s\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab2[j].name; j++)
+ if(fptab2[j].opf == i->opf){
+ bprint(i, "%s\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
+ return;
+ }
+ bprint(i, "%s%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
+}
diff --git a/libinterp/das-spim.c b/libinterp/das-spim.c
new file mode 100644
index 00000000..459a3a7c
--- /dev/null
+++ b/libinterp/das-spim.c
@@ -0,0 +1 @@
+#include "das-mips.c"
diff --git a/libinterp/das-stub.c b/libinterp/das-stub.c
new file mode 100644
index 00000000..115e0b46
--- /dev/null
+++ b/libinterp/das-stub.c
@@ -0,0 +1,9 @@
+#include <lib9.h>
+#include <kernel.h>
+
+void
+das(uchar *x, int n)
+{
+ USED(x);
+ USED(n);
+}
diff --git a/libinterp/das-thumb.c b/libinterp/das-thumb.c
new file mode 100644
index 00000000..2609bbe5
--- /dev/null
+++ b/libinterp/das-thumb.c
@@ -0,0 +1,548 @@
+#include <lib9.h>
+
+typedef struct Instr Instr;
+struct Instr
+{
+ ulong w;
+ ulong addr;
+ uchar op; /* super opcode */
+
+ uchar rd;
+ uchar rn;
+ uchar rs;
+
+ long imm; /* imm */
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+ char* err; /* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+ char* o;
+ void (*f)(Opcode*, Instr*);
+ int unused; /* remove field some time */
+ char* a;
+};
+
+static void format(char*, Instr*, char*);
+static int thumbinst(ulong, char, char*, int);
+static int thumbdas(ulong, char*, int);
+
+static
+char* cond[16] =
+{
+ "EQ", "NE", "CS", "CC",
+ "MI", "PL", "VS", "VC",
+ "HI", "LS", "GE", "LT",
+ "GT", "LE", 0, "NV"
+};
+
+static int
+get4(ulong addr, long *v)
+{
+ *v = *(ulong*)addr;
+ return 1;
+}
+
+static int
+get2(ulong addr, ushort *v)
+{
+ *v = *(ushort*)addr;
+ return 1;
+}
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+#define B(h, l) bits(ins, h, l)
+
+static int
+bits(int i, int h, int l)
+{
+ if(h < l)
+ print("h < l in bits");
+ return (i&(((1<<(h-l+1))-1)<<l))>>l;
+}
+
+int
+thumbclass(long w)
+{
+ int o;
+ int ins = w;
+
+ if(ins&0xffff0000)
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2;
+ o = B(15, 13);
+ switch(o){
+ case 0:
+ o = B(12, 11);
+ switch(o){
+ case 0:
+ case 1:
+ case 2:
+ return B(12, 11);
+ case 3:
+ if(B(10, 10) == 0)
+ return 3+B(9, 9);
+ else
+ return 3+2+B(9, 9);
+ }
+ case 1:
+ return 3+2+2+B(12, 11);
+ case 2:
+ o = B(12, 10);
+ if(o == 0)
+ return 3+2+2+4+B(9, 6);
+ if(o == 1){
+ o = B(9, 8);
+ if(o == 3)
+ return 3+2+2+4+16+B(9, 8);
+ return 3+2+2+4+16+B(9, 8);
+ }
+ if(o == 2 || o == 3)
+ return 3+2+2+4+16+4;
+ return 3+2+2+4+16+4+1+B(11, 9);
+ case 3:
+ return 3+2+2+4+16+4+1+8+B(12, 11);
+ case 4:
+ if(B(12, 12) == 0)
+ return 3+2+2+4+16+4+1+8+4+B(11, 11);
+ return 3+2+2+4+16+4+1+8+6+B(11, 11);
+ case 5:
+ if(B(12, 12) == 0)
+ return 3+2+2+4+16+4+1+8+6+2+B(11, 11);
+ if(B(11, 8) == 0)
+ return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7);
+ return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11);
+ case 6:
+ if(B(12, 12) == 0)
+ return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11);
+ if(B(11, 8) == 0xf)
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4;
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1;
+ case 7:
+ o = B(12, 11);
+ switch(o){
+ case 0:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1;
+ case 1:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2;
+ case 2:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1;
+ case 3:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1;
+ }
+ }
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+ ushort w;
+
+ get2(pc, &w);
+ i->w = w;
+ i->addr = pc;
+ i->op = thumbclass(w);
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+thumbshift(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->imm = B(10, 6);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbrrr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->rs = B(8, 6);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbirr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->imm = B(8, 6);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbir(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(10, 8);
+ i->imm = B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbrr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbrrh(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ if(B(6, 6))
+ i->rn += 8;
+ if(B(7, 7))
+ i->rd += 8;
+ if(o != nil){
+ if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770) // mov r6, pc or mov lr, pc or bx r6 or bx lr
+ format("RET", i, "");
+ else
+ format(o->o, i, o->a);
+ }
+}
+
+static void
+thumbpcrel(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rn = 15;
+ i->rd = B(10, 8);
+ i->imm = 4*(B(7, 0)+1);
+ if(i->addr & 3)
+ i->imm -= 2;
+ format(o->o, i, o->a);
+}
+
+static void
+thumbmovirr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->imm = B(10, 6);
+ if(strcmp(o->o, "MOVW") == 0)
+ i->imm *= 4;
+ else if(strncmp(o->o, "MOVH", 4) == 0)
+ i->imm *= 2;
+ format(o->o, i, o->a);
+}
+
+static void
+thumbmovsp(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rn = 13;
+ i->rd = B(10, 8);
+ i->imm = 4*B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbaddsppc(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(10, 8);
+ i->imm = 4*B(7, 0);
+ if(i->op == 48)
+ i->imm += 4;
+ format(o->o, i, o->a);
+}
+
+static void
+thumbaddsp(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->imm = 4*B(6, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbswi(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->imm = B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbbcc(Opcode *o, Instr *i)
+{
+ int off, ins = i->w;
+
+ off = B(7, 0);
+ if(off & 0x80)
+ off |= 0xffffff00;
+ i->imm = i->addr + 2*off + 4;
+ if(o != nil)
+ format(o->o, i, o->a);
+}
+
+static void
+thumbb(Opcode *o, Instr *i)
+{
+ int off, ins = i->w;
+
+ off = B(10, 0);
+ if(off & 0x400)
+ off |= 0xfffff800;
+ i->imm = i->addr + 2*off + 4;
+ if(o != nil)
+ format(o->o, i, o->a);
+}
+
+static void
+thumbbl(Opcode *o, Instr *i)
+{
+ int off, h, ins = i->w;
+ static int reglink;
+
+ h = B(11, 11);
+ off = B(10, 0);
+ if(h == 0){
+ if(off & 0x400)
+ off |= 0xfffff800;
+ i->imm = i->addr + (off<<12) + 4;
+ reglink = i->imm;
+ }
+ else{
+ i->imm = reglink + 2*off;
+ }
+ if(o != nil)
+ format(o->o, i, o->a);
+}
+
+static void
+thumbregs(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ if(i->op == 52 || i->op == 53)
+ i->rd = 13;
+ else
+ i->rd = B(10, 8);
+ i->imm = B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbunk(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static Opcode opcodes[] =
+{
+ "LSL", thumbshift, 0, "$#%i,R%n,R%d", // 0
+ "LSR", thumbshift, 0, "$#%i,R%n,R%d", // 1
+ "ASR", thumbshift, 0, "$#%i,R%n,R%d", // 2
+ "ADD", thumbrrr, 0, "R%s,R%n,R%d", // 3
+ "SUB", thumbrrr, 0, "R%s,R%n,R%d", // 4
+ "ADD", thumbirr, 0, "$#%i,R%n,R%d", // 5
+ "SUB", thumbirr, 0, "$#%i,R%n,R%d", // 6
+ "MOVW", thumbir, 0, "$#%i,R%d", // 7
+ "CMP", thumbir, 0, "$#%i,R%d", // 8
+ "ADD", thumbir, 0, "$#%i,R%d,R%d", // 9
+ "SUB", thumbir, 0, "$#%i,R%d,R%d", // 10
+ "AND", thumbrr, 0, "R%n,R%d,R%d", // 11
+ "EOR", thumbrr, 0, "R%n,R%d,R%d", // 12
+ "LSL", thumbrr, 0, "R%n,R%d,R%d", // 13
+ "LSR", thumbrr, 0, "R%n,R%d,R%d", // 14
+ "ASR", thumbrr, 0, "R%n,R%d,R%d", // 15
+ "ADC", thumbrr, 0, "R%n,R%d,R%d", // 16
+ "SBC", thumbrr, 0, "R%n,R%d,R%d", // 17
+ "ROR", thumbrr, 0, "R%n,R%d,R%d", // 18
+ "TST", thumbrr, 0, "R%n,R%d", // 19
+ "NEG", thumbrr, 0, "R%n,R%d", // 20
+ "CMP", thumbrr, 0, "R%n,R%d", // 21
+ "CMPN", thumbrr, 0, "R%n,R%d", // 22
+ "OR", thumbrr, 0, "R%n,R%d,R%d", // 23
+ "MUL", thumbrr, 0, "R%n,R%d,R%d", // 24
+ "BITC", thumbrr, 0, "R%n,R%d,R%d", // 25
+ "MOVN", thumbrr, 0, "R%n,R%d", // 26
+ "ADD", thumbrrh, 0, "R%n,R%d,R%d", // 27
+ "CMP", thumbrrh, 0, "R%n,R%d", // 28
+ "MOVW", thumbrrh, 0, "R%n,R%d", // 29
+ "BX", thumbrrh, 0, "R%n", // 30
+ "MOVW", thumbpcrel, 0, "%i(PC),R%d", // 31
+ "MOVW", thumbrrr, 0, "R%d, [R%s,R%n]", // 32
+ "MOVH", thumbrrr, 0, "R%d, [R%s,R%n]", // 33
+ "MOVB", thumbrrr, 0, "R%d, [R%s,R%n]", // 34
+ "MOVB", thumbrrr, 0, "[R%s,R%n],R%d", // 35
+ "MOVW", thumbrrr, 0, "[R%s,R%n],R%d", // 36
+ "MOVHU", thumbrrr, 0, "[R%s,R%n],R%d", // 37
+ "MOVBU", thumbrrr, 0, "[R%s,R%n],R%d", // 38
+ "MOVH", thumbrrr, 0, "[R%s,R%n],R%d", // 39
+ "MOVW", thumbmovirr, 0, "R%d,%i(R%n)", // 40
+ "MOVW", thumbmovirr, 0, "%i(R%n),R%d", // 41
+ "MOVB", thumbmovirr, 0, "R%d,%i(R%n)", // 42
+ "MOVBU", thumbmovirr, 0, "%i(R%n),R%d", // 43
+ "MOVH", thumbmovirr, 0, "R%d,%i(R%n)", // 44
+ "MOVHU", thumbmovirr, 0, "%i(R%n),R%d", // 45
+ "MOVW", thumbmovsp, 0, "R%d,%i(SP)", // 46
+ "MOVW", thumbmovsp, 0, "%i(SP),R%d", // 47
+ "ADD", thumbaddsppc,0, "$#%i,PC,R%d", // 48
+ "ADD", thumbaddsppc,0, "$#%i,SP,R%d", // 49
+ "ADD", thumbaddsp, 0, "$#%i,SP,SP", // 50
+ "SUB", thumbaddsp, 0, "$#%i,SP,SP", // 51
+ "PUSH", thumbregs, 0, "R%d, %r", // 52
+ "POP", thumbregs, 0, "R%d, %r", // 53
+ "STMIA", thumbregs, 0, "R%d, %r", // 54
+ "LDMIA", thumbregs, 0, "R%d, %r", // 55
+ "SWI", thumbswi, 0, "$#%i", // 56
+ "B%c", thumbbcc, 0, "%b", // 57
+ "B", thumbb, 0, "%b", // 58
+ "BL", thumbbl, 0, "", // 59
+ "BL", thumbbl, 0, "%b", // 60
+ "UNK", thumbunk, 0, "", // 61
+};
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int j, k, m, n;
+ int ins = i->w;
+
+ if(mnemonic)
+ format(0, i, mnemonic);
+ if(f == 0)
+ return;
+ if(mnemonic)
+ if(i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if(*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 'c': /* Bcc */
+ bprint(i, "%s", cond[B(11, 8)]);
+ break;
+
+ case 's':
+ bprint(i, "%d", i->rs);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->rn);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'i':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'b':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'r':
+ n = i->imm&0xff;
+ j = 0;
+ k = 0;
+ while(n) {
+ m = j;
+ while(n&0x1) {
+ j++;
+ n >>= 1;
+ }
+ if(j != m) {
+ if(k)
+ bprint(i, ",");
+ if(j == m+1)
+ bprint(i, "R%d", m);
+ else
+ bprint(i, "R%d-R%d", m, j-1);
+ k = 1;
+ }
+ j++;
+ n >>= 1;
+ }
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+void
+das(ulong *x, int n)
+{
+ ulong pc;
+ Instr i;
+ char buf[128];
+
+ pc = (ulong)x;
+ while(n > 0) {
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+
+ if(decode(pc, &i) < 0)
+ sprint(buf, "???");
+ else
+ (*opcodes[i.op].f)(&opcodes[i.op], &i);
+
+ print("%.8lux %.8lux\t%s\n", pc, i.w, buf);
+ pc += 2;
+ n--;
+ }
+}
diff --git a/libinterp/dec.c b/libinterp/dec.c
new file mode 100644
index 00000000..d8169947
--- /dev/null
+++ b/libinterp/dec.c
@@ -0,0 +1,1811 @@
+/* Machine generated by decgen.c */
+
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)
+static void
+D00(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D01(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D02(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D03(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D04(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D05(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D06(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D07(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D08(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D09(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D0A(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D0B(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D0C(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D0D(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D0E(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D0F(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D10(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D11(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D12(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D13(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D14(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D15(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D16(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D17(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D18(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D19(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D1A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D1B(void)
+{
+}
+static void
+D1C(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D1D(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D1E(void)
+{
+}
+static void
+D1F(void)
+{
+}
+static void
+D20(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D21(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D22(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D23(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D24(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D25(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D26(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D27(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D28(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D29(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D2A(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D2B(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D2C(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D2D(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D2E(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D2F(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D30(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D31(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D32(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D33(void)
+{
+}
+static void
+D34(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D35(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D36(void)
+{
+}
+static void
+D37(void)
+{
+}
+static void
+D38(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D39(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D3A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D3B(void)
+{
+}
+static void
+D3C(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D3D(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D3E(void)
+{
+}
+static void
+D3F(void)
+{
+}
+static void
+D40(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D41(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D42(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D43(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D44(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D45(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D46(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D47(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D48(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D49(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4A(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4B(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D4C(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4D(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4E(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D4F(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D50(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D51(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D52(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D53(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D54(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D55(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D56(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D57(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D58(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D59(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5B(void)
+{
+}
+static void
+D5C(void)
+{
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5D(void)
+{
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5E(void)
+{
+}
+static void
+D5F(void)
+{
+}
+static void
+D60(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D61(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D62(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D63(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D64(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D65(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D66(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D67(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D68(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D69(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6A(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6B(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D6C(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6D(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6E(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D6F(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D70(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D71(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D72(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D73(void)
+{
+}
+static void
+D74(void)
+{
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D75(void)
+{
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D76(void)
+{
+}
+static void
+D77(void)
+{
+}
+static void
+D78(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D79(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7B(void)
+{
+}
+static void
+D7C(void)
+{
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7D(void)
+{
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7E(void)
+{
+}
+static void
+D7F(void)
+{
+}
+static void
+D80(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D81(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D82(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D83(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D84(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D85(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D86(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D87(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D88(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D89(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8A(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8B(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D8C(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8D(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8E(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D8F(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D90(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D91(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D92(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D93(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D94(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D95(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D96(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D97(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D98(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D99(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9B(void)
+{
+}
+static void
+D9C(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9D(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9E(void)
+{
+}
+static void
+D9F(void)
+{
+}
+static void
+DA0(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA1(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA2(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA3(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DA4(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA5(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA6(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DA7(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DA8(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA9(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAA(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAB(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DAC(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAD(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAE(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DAF(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DB0(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB1(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB2(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB3(void)
+{
+}
+static void
+DB4(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB5(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB6(void)
+{
+}
+static void
+DB7(void)
+{
+}
+static void
+DB8(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB9(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBA(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBB(void)
+{
+}
+static void
+DBC(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBD(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBE(void)
+{
+}
+static void
+DBF(void)
+{
+}
+static void
+DC0(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC1(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC2(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC3(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC4(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC5(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC6(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC7(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC8(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC9(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCA(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCB(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+DCC(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCD(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCE(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+DCF(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+DD0(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD1(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD2(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD3(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD4(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD5(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD6(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD7(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD8(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD9(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDA(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDB(void)
+{
+}
+static void
+DDC(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDD(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDE(void)
+{
+}
+static void
+DDF(void)
+{
+}
+static void
+DE0(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE1(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE2(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE3(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DE4(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE5(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE6(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DE7(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DE8(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE9(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DEA(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DEB(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DEC(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DED(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DEE(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DEF(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DF0(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF1(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF2(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF3(void)
+{
+}
+static void
+DF4(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF5(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF6(void)
+{
+}
+static void
+DF7(void)
+{
+}
+static void
+DF8(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF9(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFA(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFB(void)
+{
+}
+static void
+DFC(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFD(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFE(void)
+{
+}
+static void
+DFF(void)
+{
+}
+
+void (*dec[])(void) =
+{
+ D00,
+ D01,
+ D02,
+ D03,
+ D04,
+ D05,
+ D06,
+ D07,
+ D08,
+ D09,
+ D0A,
+ D0B,
+ D0C,
+ D0D,
+ D0E,
+ D0F,
+ D10,
+ D11,
+ D12,
+ D13,
+ D14,
+ D15,
+ D16,
+ D17,
+ D18,
+ D19,
+ D1A,
+ D1B,
+ D1C,
+ D1D,
+ D1E,
+ D1F,
+ D20,
+ D21,
+ D22,
+ D23,
+ D24,
+ D25,
+ D26,
+ D27,
+ D28,
+ D29,
+ D2A,
+ D2B,
+ D2C,
+ D2D,
+ D2E,
+ D2F,
+ D30,
+ D31,
+ D32,
+ D33,
+ D34,
+ D35,
+ D36,
+ D37,
+ D38,
+ D39,
+ D3A,
+ D3B,
+ D3C,
+ D3D,
+ D3E,
+ D3F,
+ D40,
+ D41,
+ D42,
+ D43,
+ D44,
+ D45,
+ D46,
+ D47,
+ D48,
+ D49,
+ D4A,
+ D4B,
+ D4C,
+ D4D,
+ D4E,
+ D4F,
+ D50,
+ D51,
+ D52,
+ D53,
+ D54,
+ D55,
+ D56,
+ D57,
+ D58,
+ D59,
+ D5A,
+ D5B,
+ D5C,
+ D5D,
+ D5E,
+ D5F,
+ D60,
+ D61,
+ D62,
+ D63,
+ D64,
+ D65,
+ D66,
+ D67,
+ D68,
+ D69,
+ D6A,
+ D6B,
+ D6C,
+ D6D,
+ D6E,
+ D6F,
+ D70,
+ D71,
+ D72,
+ D73,
+ D74,
+ D75,
+ D76,
+ D77,
+ D78,
+ D79,
+ D7A,
+ D7B,
+ D7C,
+ D7D,
+ D7E,
+ D7F,
+ D80,
+ D81,
+ D82,
+ D83,
+ D84,
+ D85,
+ D86,
+ D87,
+ D88,
+ D89,
+ D8A,
+ D8B,
+ D8C,
+ D8D,
+ D8E,
+ D8F,
+ D90,
+ D91,
+ D92,
+ D93,
+ D94,
+ D95,
+ D96,
+ D97,
+ D98,
+ D99,
+ D9A,
+ D9B,
+ D9C,
+ D9D,
+ D9E,
+ D9F,
+ DA0,
+ DA1,
+ DA2,
+ DA3,
+ DA4,
+ DA5,
+ DA6,
+ DA7,
+ DA8,
+ DA9,
+ DAA,
+ DAB,
+ DAC,
+ DAD,
+ DAE,
+ DAF,
+ DB0,
+ DB1,
+ DB2,
+ DB3,
+ DB4,
+ DB5,
+ DB6,
+ DB7,
+ DB8,
+ DB9,
+ DBA,
+ DBB,
+ DBC,
+ DBD,
+ DBE,
+ DBF,
+ DC0,
+ DC1,
+ DC2,
+ DC3,
+ DC4,
+ DC5,
+ DC6,
+ DC7,
+ DC8,
+ DC9,
+ DCA,
+ DCB,
+ DCC,
+ DCD,
+ DCE,
+ DCF,
+ DD0,
+ DD1,
+ DD2,
+ DD3,
+ DD4,
+ DD5,
+ DD6,
+ DD7,
+ DD8,
+ DD9,
+ DDA,
+ DDB,
+ DDC,
+ DDD,
+ DDE,
+ DDF,
+ DE0,
+ DE1,
+ DE2,
+ DE3,
+ DE4,
+ DE5,
+ DE6,
+ DE7,
+ DE8,
+ DE9,
+ DEA,
+ DEB,
+ DEC,
+ DED,
+ DEE,
+ DEF,
+ DF0,
+ DF1,
+ DF2,
+ DF3,
+ DF4,
+ DF5,
+ DF6,
+ DF7,
+ DF8,
+ DF9,
+ DFA,
+ DFB,
+ DFC,
+ DFD,
+ DFE,
+ DFF
+};
diff --git a/libinterp/decgen.c b/libinterp/decgen.c
new file mode 100644
index 00000000..f81749c7
--- /dev/null
+++ b/libinterp/decgen.c
@@ -0,0 +1,122 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+void decgen(int);
+
+/*
+ * Force intermediate dereference of $o(o(reg)) modes to ensure intermediate
+ * pointer is valid. This is required if you want secure memory.
+ */
+#define SOFTMMU 0
+
+void
+main(void)
+{
+ int i;
+
+ print("/* Machine generated by decgen.c */\n\n");
+
+ print("#include \"lib9.h\"\n");
+ print("#include \"isa.h\"\n");
+ print("#include \"interp.h\"\n\n");
+
+ print("#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)\n");
+
+ for(i = 0; i < 256; i++)
+ decgen(i);
+
+ print("\nvoid (*dec[])(void) =\n{\n");
+ for(i = 0; i < 256; i++)
+ print("\tD%.2uX%c\n", i, i != 255 ? ',' : ' ');
+ print("};\n");
+}
+
+void
+decgen(int addr)
+{
+ int nodst;
+
+ print("static void\nD%.2uX(void)\n{\n", addr);
+
+ switch(USRC(addr)) {
+ case AMP:
+ print("\tR.s = R.MP+R.PC->s.ind;\n");
+ break;
+ case AFP:
+ print("\tR.s = R.FP+R.PC->s.ind;\n");
+ break;
+ case AIMM:
+ print("\tR.s = (uchar*)&R.PC->s.imm;\n");
+ break;
+ case AMP|AIND:
+ if(SOFTMMU) {
+ print("R.s = R.MP+R.PC->s.i.f\n");
+ print("R.s = *(WORD**)R.s\n");
+ print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
+ }
+ else
+ print("\tR.s = DIND(MP, s);\n");
+ break;
+ case AFP|AIND:
+ if(SOFTMMU) {
+ print("R.s = R.FP+R.PC->s.i.f\n");
+ print("R.s = *(WORD**)R.s\n");
+ print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
+ }
+ else
+ print("\tR.s = DIND(FP, s);\n");
+ break;
+ }
+ nodst = 0;
+ switch(UDST(addr)) {
+ default:
+ nodst = 1;
+ break;
+ case AMP:
+ print("\tR.d = R.MP+R.PC->d.ind;\n");
+ break;
+ case AFP:
+ print("\tR.d = R.FP+R.PC->d.ind;\n");
+ break;
+ case AIMM:
+ print("\tR.d = (uchar*)&R.PC->d.imm;\n");
+ break;
+ case AMP|AIND:
+ if(SOFTMMU) {
+ print("R.d = R.MP+R.PC->d.i.f\n");
+ print("R.d = *(WORD**)R.d\n");
+ print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
+ }
+ else
+ print("\tR.d = DIND(MP, d);\n");
+ break;
+ case AFP|AIND:
+ if(SOFTMMU) {
+ print("R.d = R.FP+R.PC->d.i.f\n");
+ print("R.d = *(WORD**)R.d\n");
+ print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
+ }
+ else
+ print("\tR.d = DIND(FP, d);\n");
+ break;
+ }
+
+ if(nodst == 0)
+ switch(addr&ARM) {
+ case AXNON:
+ print("\tR.m = R.d;\n");
+ break;
+ case AXIMM:
+ print("\tR.t = (short)R.PC->reg;\n");
+ print("\tR.m = &R.t;\n");
+ break;
+ case AXINF:
+ print("\tR.m = R.FP+R.PC->reg;\n");
+ break;
+ case AXINM:
+ print("\tR.m = R.MP+R.PC->reg;\n");
+ break;
+ }
+ print("}\n");
+}
diff --git a/libinterp/dlm-Inferno.c b/libinterp/dlm-Inferno.c
new file mode 100644
index 00000000..7b825028
--- /dev/null
+++ b/libinterp/dlm-Inferno.c
@@ -0,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define DBG if(1) print
+
+extern Dynobj* dynld(int);
+extern char* enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+ char buf[64];
+
+ if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+ return nil;
+ snprint(buf, sizeof(buf), "%s%s", pre, suf);
+ return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ Module *m;
+ void *v;
+ Runtab *r;
+ Dynobj *o;
+ char *name;
+
+ DBG("module path is %s\n", path);
+ m = nil;
+ o = dynld(fd);
+ if(o == nil){
+ DBG("%s\n", enverror());
+ goto Error;
+ }
+ v = addr("XXX", "module", o, signof(char*));
+ if(v == nil)
+ goto Error;
+ name = *(char**)v;
+ DBG("module name is %s\n", name);
+ r = addr(name, "modtab", o, signof(Runtab[]));
+ if(r == nil)
+ goto Error;
+ m = builtinmod(name, r, 0);
+ m->rt = DYNMOD;
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->path = strdup(path);
+ if(m->path == nil)
+ goto Error;
+ m->dlm = o;
+ DBG("module base is 0x%p\n", o->base);
+ return m;
+Error:
+ if(o != nil)
+ dynobjfree(o);
+ if(m != nil)
+ freemod(m);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+ void *v, (*f)(void);
+
+ if(m->ref != 1)
+ return;
+ v = addr(m->name, fn, m->dlm, signof(*f));
+ if(v != nil){
+ f = v;
+ (*f)();
+ }
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ callfn(ml->m, "end");
+}
diff --git a/libinterp/dlm-Nt.c b/libinterp/dlm-Nt.c
new file mode 100644
index 00000000..e885edcb
--- /dev/null
+++ b/libinterp/dlm-Nt.c
@@ -0,0 +1,48 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ USED(fd);
+ USED(path);
+ USED(dir);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ USED(m);
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+Dynobj*
+dynld(int fd)
+{
+ USED(fd);
+ return nil;
+}
+
+int
+dynldable(int fd)
+{
+ USED(fd);
+ return 0;
+}
diff --git a/libinterp/dlm-Plan9.c b/libinterp/dlm-Plan9.c
new file mode 100644
index 00000000..7b825028
--- /dev/null
+++ b/libinterp/dlm-Plan9.c
@@ -0,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define DBG if(1) print
+
+extern Dynobj* dynld(int);
+extern char* enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+ char buf[64];
+
+ if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+ return nil;
+ snprint(buf, sizeof(buf), "%s%s", pre, suf);
+ return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ Module *m;
+ void *v;
+ Runtab *r;
+ Dynobj *o;
+ char *name;
+
+ DBG("module path is %s\n", path);
+ m = nil;
+ o = dynld(fd);
+ if(o == nil){
+ DBG("%s\n", enverror());
+ goto Error;
+ }
+ v = addr("XXX", "module", o, signof(char*));
+ if(v == nil)
+ goto Error;
+ name = *(char**)v;
+ DBG("module name is %s\n", name);
+ r = addr(name, "modtab", o, signof(Runtab[]));
+ if(r == nil)
+ goto Error;
+ m = builtinmod(name, r, 0);
+ m->rt = DYNMOD;
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->path = strdup(path);
+ if(m->path == nil)
+ goto Error;
+ m->dlm = o;
+ DBG("module base is 0x%p\n", o->base);
+ return m;
+Error:
+ if(o != nil)
+ dynobjfree(o);
+ if(m != nil)
+ freemod(m);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+ void *v, (*f)(void);
+
+ if(m->ref != 1)
+ return;
+ v = addr(m->name, fn, m->dlm, signof(*f));
+ if(v != nil){
+ f = v;
+ (*f)();
+ }
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ callfn(ml->m, "end");
+}
diff --git a/libinterp/dlm-Posix.c b/libinterp/dlm-Posix.c
new file mode 100644
index 00000000..e885edcb
--- /dev/null
+++ b/libinterp/dlm-Posix.c
@@ -0,0 +1,48 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ USED(fd);
+ USED(path);
+ USED(dir);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ USED(m);
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+Dynobj*
+dynld(int fd)
+{
+ USED(fd);
+ return nil;
+}
+
+int
+dynldable(int fd)
+{
+ USED(fd);
+ return 0;
+}
diff --git a/libinterp/draw.c b/libinterp/draw.c
new file mode 100644
index 00000000..55dacddf
--- /dev/null
+++ b/libinterp/draw.c
@@ -0,0 +1,2345 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "drawmod.h"
+#include "draw.h"
+#include "drawif.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * When a Display is remote, it must be locked to synchronize the
+ * outgoing message buffer with the refresh demon, which runs as a
+ * different process. When it is local, the refresh demon does nothing
+ * and it is sufficient to use the interpreter's own acquire/release protection
+ * to lock the buffer.
+ *
+ * Most action to the buffer is caused by calls from Limbo, so locking at
+ * the top before going into the library is good enough. However, the
+ * garbage collector can call the free routines at other times, so they
+ * need to protect themselves whether called through the Draw module
+ * or not; hence the need for check against recursive locking in lockdisplay().
+ * This also means that we needn't lock around calls to destroy if it's
+ * extra work to do so.
+ */
+
+typedef struct Cache Cache;
+typedef struct DRef DRef;
+typedef struct DDisplay DDisplay;
+typedef struct DImage DImage;
+typedef struct DScreen DScreen;
+typedef struct DFont DFont;
+
+struct Cache
+{
+ int ref;
+ char* name;
+ Display*display;
+ union{
+ Subfont* sf;
+ Font* f;
+ void* ptr;
+ }u;
+ Cache* next;
+};
+
+/* not visible to Limbo; used only for internal reference counting */
+struct DRef
+{
+ int ref;
+ Display* display;
+};
+
+struct DDisplay
+{
+ Draw_Display drawdisplay;
+ Display* display;
+ DRef* dref;
+};
+
+struct DImage
+{
+ Draw_Image drawimage;
+ Image* image;
+ void* refreshptr;
+ DRef* dref;
+ int flush;
+};
+
+struct DScreen
+{
+ Draw_Screen drawscreen;
+ Screen* screen;
+ DRef* dref;
+};
+
+struct DFont
+{
+ Draw_Font drawfont;
+ Font* font;
+ DRef* dref;
+};
+
+Cache* sfcache[BIHASH];
+Cache* fcache[BIHASH];
+void* cacheqlock;
+
+static Cache *cachelookup(Cache**, Display*, char*);
+
+uchar fontmap[] = Draw_Font_map;
+uchar imagemap[] = Draw_Image_map;
+uchar screenmap[] = Draw_Screen_map;
+uchar displaymap[] = Draw_Display_map;
+
+Type* TFont;
+Type* TImage;
+Type* TScreen;
+Type* TDisplay;
+
+Draw_Image* allocdrawimage(DDisplay*, Draw_Rect, ulong, Image*, int, int);
+Draw_Image* color(DDisplay*, ulong);
+Draw_Screen *mkdrawscreen(Screen*, Draw_Display*);
+
+char deffontname[] = "*default*";
+void refreshslave(Display*);
+void subfont_close(Subfont*);
+void freeallsubfonts(Display*);
+
+void
+drawmodinit(void)
+{
+ TFont = dtype(freedrawfont, sizeof(DFont), fontmap, sizeof(fontmap));
+ TImage = dtype(freedrawimage, sizeof(DImage), imagemap, sizeof(imagemap));
+ TScreen = dtype(freedrawscreen, sizeof(DScreen), screenmap, sizeof(screenmap));
+ TDisplay = dtype(freedrawdisplay, sizeof(DDisplay), displaymap, sizeof(displaymap));
+ builtinmod("$Draw", Drawmodtab, Drawmodlen);
+}
+
+static int
+drawhash(char *s)
+{
+ int h;
+
+ h = 0;
+ while(*s){
+ h += *s++;
+ h <<= 1;
+ if(h & (1<<8))
+ h |= 1;
+ }
+ return (h&0xFFFF)%BIHASH;
+}
+
+static Cache*
+cachelookup(Cache *cache[], Display *d, char *name)
+{
+ Cache *c;
+
+ libqlock(cacheqlock);
+ c = cache[drawhash(name)];
+ while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0))
+ c = c->next;
+ libqunlock(cacheqlock);
+ return c;
+}
+
+Cache*
+cacheinstall(Cache **cache, Display *d, char *name, void *ptr, char *type)
+{
+ Cache *c;
+ int hash;
+
+ USED(type);
+ c = cachelookup(cache, d, name);
+ if(c){
+/* print("%s %s already in cache\n", type, name); /**/
+ return nil;
+ }
+ c = malloc(sizeof(Cache));
+ if(c == nil)
+ return nil;
+ hash = drawhash(name);
+ c->ref = 0; /* will be incremented by caller */
+ c->display = d;
+ c->name = strdup(name);
+ c->u.ptr = ptr;
+ libqlock(cacheqlock);
+ c->next = cache[hash];
+ cache[hash] = c;
+ libqunlock(cacheqlock);
+ return c;
+}
+
+void
+cacheuninstall(Cache **cache, Display *d, char *name, char *type)
+{
+ Cache *c, *prev;
+ int hash;
+
+ hash = drawhash(name);
+ libqlock(cacheqlock);
+ c = cache[hash];
+ if(c == nil){
+ Notfound:
+ libqunlock(cacheqlock);
+ print("%s not in %s cache\n", name, type);
+ return;
+ }
+ prev = nil;
+ while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)){
+ prev = c;
+ c = c->next;
+ }
+ if(c == nil)
+ goto Notfound;
+ if(prev == 0)
+ cache[hash] = c->next;
+ else
+ prev->next = c->next;
+ libqunlock(cacheqlock);
+ free(c->name);
+ free(c);
+}
+
+Image*
+lookupimage(Draw_Image *di)
+{
+ Display *disp;
+ Image *i;
+ int locked;
+
+ if(di == H || D2H(di)->t != TImage)
+ return nil;
+ i = ((DImage*)di)->image;
+ if(i == nil)
+ return nil;
+ if(!eqrect(IRECT(di->clipr), i->clipr) || di->repl!=i->repl){
+ disp = i->display;
+ locked = lockdisplay(disp);
+ replclipr(i, di->repl, IRECT(di->clipr));
+ if(locked)
+ unlockdisplay(disp);
+ }
+ return i;
+}
+
+Screen*
+lookupscreen(Draw_Screen *ds)
+{
+ if(ds == H || D2H(ds)->t != TScreen)
+ return nil;
+ return ((DScreen*)ds)->screen;
+}
+
+Font*
+lookupfont(Draw_Font *df)
+{
+ if(df == H || D2H(df)->t != TFont)
+ return nil;
+ return ((DFont*)df)->font;
+}
+
+Display*
+lookupdisplay(Draw_Display *dd)
+{
+ if(dd == H || D2H(dd)->t != TDisplay)
+ return nil;
+ return ((DDisplay*)dd)->display;
+}
+
+Image*
+checkimage(Draw_Image *di)
+{
+ Image *i;
+
+ if(di == H)
+ error("nil Image");
+ i = lookupimage(di);
+ if(i == nil)
+ error(exType);
+ return i;
+}
+
+Screen*
+checkscreen(Draw_Screen *ds)
+{
+ Screen *s;
+
+ if(ds == H)
+ error("nil Screen");
+ s = lookupscreen(ds);
+ if(s == nil)
+ error(exType);
+ return s;
+}
+
+Font*
+checkfont(Draw_Font *df)
+{
+ Font *f;
+
+ if(df == H)
+ error("nil Font");
+ f = lookupfont(df);
+ if(f == nil)
+ error(exType);
+ return f;
+}
+
+Display*
+checkdisplay(Draw_Display *dd)
+{
+ Display *d;
+
+ if(dd == H)
+ error("nil Display");
+ d = lookupdisplay(dd);
+ if(d == nil)
+ error(exType);
+ return d;
+}
+
+void
+Display_allocate(void *fp)
+{
+ F_Display_allocate *f;
+ char buf[128], *dev;
+ Subfont *df;
+ Display *display;
+ DDisplay *dd;
+ Heap *h;
+ Draw_Rect r;
+ DRef *dr;
+ Cache *c;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ if(cacheqlock == nil){
+ cacheqlock = libqlalloc();
+ if(cacheqlock == nil)
+ return;
+ }
+ dev = string2c(f->dev);
+ if(dev[0] == 0)
+ dev = 0;
+ display = initdisplay(dev, dev, nil); /* TO DO: win, error */
+ if(display == 0)
+ return;
+
+ dr = malloc(sizeof(DRef));
+ if(dr == nil)
+ return;
+ h = heap(TDisplay);
+ if(h == H){
+ closedisplay(display);
+ return;
+ }
+ dd = H2D(DDisplay*, h);
+ dd->display = display;
+ *f->ret = &dd->drawdisplay;
+ dd->dref = dr;
+ display->limbo = dr;
+ dr->display = display;
+ dr->ref = 1;
+ df = getdefont(display);
+ if(df){
+ display->defaultsubfont = df;
+ sprint(buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
+ df->n-1, deffontname);
+ display->defaultfont = buildfont(display, buf, deffontname);
+ if(display->defaultfont){
+ c = cacheinstall(fcache, display, deffontname, display->defaultfont, "font");
+ if(c)
+ c->ref++;
+ /* else BUG? */
+ }
+ }
+
+ R2R(r, display->image->r);
+ dd->drawdisplay.image = allocdrawimage(dd, r, display->image->chan, display->image, 0, 0);
+ R2R(r, display->white->r);
+ dd->drawdisplay.black = allocdrawimage(dd, r, display->black->chan, display->black, 1, 0);
+ dd->drawdisplay.white = allocdrawimage(dd, r, display->white->chan, display->white, 1, 0);
+ dd->drawdisplay.opaque = allocdrawimage(dd, r, display->opaque->chan, display->opaque, 1, 0);
+ dd->drawdisplay.transparent = allocdrawimage(dd, r, display->transparent->chan, display->transparent, 1, 0);
+
+ /* don't call unlockdisplay because the qlock was left up by initdisplay */
+ libqunlock(display->qlock);
+}
+
+void
+Display_getwindow(void *fp)
+{
+ F_Display_getwindow *f;
+ Display *disp;
+ int locked;
+ Image *image;
+ Screen *screen;
+ char *wn;
+ void *r;
+
+ f = fp;
+ r = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(r);
+ r = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(r);
+ disp = checkdisplay(f->d);
+ if(f->winname == H)
+ wn = "/dev/winname";
+ else
+ wn = string2c(f->winname);
+ if(f->image == H)
+ image = nil;
+ else
+ image = checkimage(f->image);
+ if(f->screen == H)
+ screen = nil;
+ else
+ screen = checkscreen(f->screen);
+ locked = lockdisplay(disp);
+ if(gengetwindow(disp, wn, &image, &screen, f->backup) < 0){
+ /* TO DO: eliminate f->image and f->screen's references to Image and Screen */
+ goto Return;
+ }
+ if(screen != nil){
+ if(f->screen != H){
+ f->ret->t0 = f->screen;
+ D2H(f->screen)->ref++;
+ }else
+ f->ret->t0 = mkdrawscreen(screen, f->d);
+ }
+ if(image != nil){
+ if(f->image != H){
+ f->ret->t1 = f->image;
+ D2H(f->image)->ref++;
+ }else
+ f->ret->t1 = mkdrawimage(image, f->ret->t0, f->d, nil);
+ }
+
+Return:
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Display_startrefresh(void *fp)
+{
+ F_Display_startrefresh *f;
+ Display *disp;
+
+ f = fp;
+ disp = checkdisplay(f->d);
+ refreshslave(disp);
+}
+
+void
+display_dec(void *v)
+{
+ DRef *dr;
+ Display *d;
+ int locked;
+
+ dr = v;
+ if(dr->ref-- != 1)
+ return;
+
+ d = dr->display;
+ locked = lockdisplay(d);
+ font_close(d->defaultfont);
+ subfont_close(d->defaultsubfont);
+ if(locked)
+ unlockdisplay(d);
+ freeallsubfonts(d);
+ closedisplay(d);
+ free(dr);
+}
+
+void
+freedrawdisplay(Heap *h, int swept)
+{
+ DDisplay *dd;
+ Display *d;
+
+ dd = H2D(DDisplay*, h);
+
+ if(!swept) {
+ destroy(dd->drawdisplay.image);
+ destroy(dd->drawdisplay.black);
+ destroy(dd->drawdisplay.white);
+ destroy(dd->drawdisplay.opaque);
+ destroy(dd->drawdisplay.transparent);
+ }
+ /* we've now released dd->image etc.; make sure they're not freed again */
+ d = dd->display;
+ d->image = nil;
+ d->white = nil;
+ d->black = nil;
+ d->opaque = nil;
+ d->transparent = nil;
+ display_dec(dd->dref);
+ /* Draw_Display header will be freed by caller */
+}
+
+void
+Display_color(void *fp)
+{
+ F_Display_color *f;
+ Display *d;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ d = checkdisplay(f->d);
+ locked = lockdisplay(d);
+ *f->ret = color((DDisplay*)f->d, f->color);
+ if(locked)
+ unlockdisplay(d);
+}
+
+void
+Image_flush(void *fp)
+{
+ F_Image_flush *f;
+ Image *d;
+ DImage *di;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->win);
+ di = (DImage*)f->win;
+ switch(f->func){
+ case 0: /* Draw->Flushoff */
+ di->flush = 0;
+ break;
+ case 1: /* Draw->Flushon */
+ di->flush = 1;
+ /* fall through */
+ case 2: /* Draw->Flushnow */
+ locked = lockdisplay(d->display);
+ if(d->id==0 || d->screen!=0)
+ flushimage(d->display, 1);
+ if(locked)
+ unlockdisplay(d->display);
+ break;
+ default:
+ error(exInval);
+ }
+}
+
+void
+checkflush(Draw_Image *dst)
+{
+ DImage *di;
+
+ di = (DImage*)dst;
+ if(di->flush && (di->image->id==0 || di->image->screen!=nil))
+ flushimage(di->image->display, 1);
+}
+
+static void
+imagedraw(void *fp, int op)
+{
+ F_Image_draw *f;
+ Image *d, *s, *m;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ if(f->src == H)
+ s = d->display->black;
+ else
+ s = checkimage(f->src);
+ if(f->matte == H)
+ m = d->display->white; /* ones */
+ else
+ m = checkimage(f->matte);
+ if(d->display!=s->display || d->display!=m->display)
+ return;
+ locked = lockdisplay(d->display);
+ drawop(d, IRECT(f->r), s, m, IPOINT(f->p), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_draw(void *fp)
+{
+ imagedraw(fp, SoverD);
+}
+
+void
+Image_drawop(void *fp)
+{
+ F_Image_drawop *f;
+
+ f = fp;
+ imagedraw(fp, f->op);
+}
+
+static void
+imagegendraw(void *fp, int op)
+{
+ F_Image_gendraw *f;
+ Image *d, *s, *m;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ if(f->src == H)
+ s = d->display->black;
+ else
+ s = checkimage(f->src);
+ if(f->matte == H)
+ m = d->display->white; /* ones */
+ else
+ m = checkimage(f->matte);
+ if(d->display!=s->display || d->display!=m->display)
+ return;
+ locked = lockdisplay(d->display);
+ gendrawop(d, IRECT(f->r), s, IPOINT(f->p0), m, IPOINT(f->p1), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_gendraw(void *fp)
+{
+ imagegendraw(fp, SoverD);
+}
+
+void
+Image_gendrawop(void *fp)
+{
+ F_Image_gendrawop *f;
+
+ f = fp;
+ imagegendraw(fp, f->op);
+}
+
+static void
+drawline(void *fp, int op)
+{
+ F_Image_line *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->radius < 0)
+ return;
+ locked = lockdisplay(d->display);
+ lineop(d, IPOINT(f->p0), IPOINT(f->p1), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_line(void *fp)
+{
+ drawline(fp, SoverD);
+}
+
+void
+Image_lineop(void *fp)
+{
+ F_Image_lineop *f;
+
+ f = fp;
+ drawline(fp, f->op);
+}
+
+static void
+drawsplinepoly(void *fp, int smooth, int op)
+{
+ F_Image_poly *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display|| f->radius < 0)
+ return;
+ locked = lockdisplay(d->display);
+ /* sleazy: we know that Draw_Points have same shape as Points */
+ if(smooth)
+ bezsplineop(d, (Point*)f->p->data, f->p->len,
+ f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+ else
+ polyop(d, (Point*)f->p->data, f->p->len, f->end0,
+ f->end1, f->radius, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_poly(void *fp)
+{
+ drawsplinepoly(fp, 0, SoverD);
+}
+
+void
+Image_polyop(void *fp)
+{
+ F_Image_polyop *f;
+
+ f = fp;
+ drawsplinepoly(fp, 0, f->op);
+}
+
+void
+Image_bezspline(void *fp)
+{
+ drawsplinepoly(fp, 1, SoverD);
+}
+
+void
+Image_bezsplineop(void *fp)
+{
+ F_Image_bezsplineop *f;
+
+ f = fp;
+ drawsplinepoly(fp, 1, f->op);
+}
+
+static void
+drawbezier(void *fp, int op)
+{
+ F_Image_bezier *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->radius < 0)
+ return;
+ locked = lockdisplay(d->display);
+ bezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
+ IPOINT(f->d), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_bezier(void *fp)
+{
+ drawbezier(fp, SoverD);
+}
+
+void
+Image_bezierop(void *fp)
+{
+ F_Image_bezierop *f;
+
+ f = fp;
+ drawbezier(fp, f->op);
+}
+
+static void
+drawfillbezier(void *fp, int op)
+{
+ F_Image_fillbezier *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display)
+ return;
+ locked = lockdisplay(d->display);
+ fillbezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
+ IPOINT(f->d), f->wind, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_fillbezier(void *fp)
+{
+ drawfillbezier(fp, SoverD);
+}
+
+void
+Image_fillbezierop(void *fp)
+{
+ F_Image_fillbezierop *f;
+
+ f = fp;
+ drawfillbezier(fp, f->op);
+}
+
+static void
+drawfillsplinepoly(void *fp, int smooth, int op)
+{
+ F_Image_fillpoly *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display)
+ return;
+ locked = lockdisplay(d->display);
+ /* sleazy: we know that Draw_Points have same shape as Points */
+ if(smooth)
+ fillbezsplineop(d, (Point*)f->p->data, f->p->len,
+ f->wind, s, IPOINT(f->sp), op);
+ else
+ fillpolyop(d, (Point*)f->p->data, f->p->len,
+ f->wind, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_fillpoly(void *fp)
+{
+ drawfillsplinepoly(fp, 0, SoverD);
+}
+
+void
+Image_fillpolyop(void *fp)
+{
+ F_Image_fillpolyop *f;
+
+ f = fp;
+ drawfillsplinepoly(fp, 0, f->op);
+}
+
+void
+Image_fillbezspline(void *fp)
+{
+ drawfillsplinepoly(fp, 1, SoverD);
+}
+
+void
+Image_fillbezsplineop(void *fp)
+{
+ F_Image_fillbezsplineop *f;
+
+ f = fp;
+ drawfillsplinepoly(fp, 1, f->op);
+}
+
+static void
+drawarcellipse(void *fp, int isarc, int alpha, int phi, int op)
+{
+ F_Image_arc *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->thick < 0 || f->a<0 || f->b<0)
+ return;
+
+ locked = lockdisplay(d->display);
+ if(isarc)
+ arcop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
+ IPOINT(f->sp), alpha, phi, op);
+ else
+ ellipseop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
+ IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_ellipse(void *fp)
+{
+ drawarcellipse(fp, 0, 0, 0, SoverD);
+}
+
+void
+Image_ellipseop(void *fp)
+{
+ F_Image_ellipseop *f;
+
+ f = fp;
+ drawarcellipse(fp, 0, 0, 0, f->op);
+}
+
+void
+Image_arc(void *fp)
+{
+ F_Image_arc *f;
+
+ f = fp;
+ drawarcellipse(fp, 1, f->alpha, f->phi, SoverD);
+}
+
+void
+Image_arcop(void *fp)
+{
+ F_Image_arcop *f;
+
+ f = fp;
+ drawarcellipse(fp, 1, f->alpha, f->phi, f->op);
+}
+
+static void
+drawfillarcellipse(void *fp, int isarc, int alpha, int phi, int op)
+{
+ F_Image_fillarc *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->a<0 || f->b<0)
+ return;
+
+ locked = lockdisplay(d->display);
+ if(isarc)
+ fillarcop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), alpha, phi, op);
+ else
+ fillellipseop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_fillellipse(void *fp)
+{
+ drawfillarcellipse(fp, 0, 0, 0, SoverD);
+}
+
+void
+Image_fillellipseop(void *fp)
+{
+ F_Image_fillellipseop *f;
+
+ f = fp;
+ drawfillarcellipse(fp, 0, 0, 0, f->op);
+}
+
+void
+Image_fillarc(void *fp)
+{
+ F_Image_fillarc *f;
+
+ f = fp;
+ drawfillarcellipse(fp, 1, f->alpha, f->phi, SoverD);
+}
+
+void
+Image_fillarcop(void *fp)
+{
+ F_Image_fillarcop *f;
+
+ f = fp;
+ drawfillarcellipse(fp, 1, f->alpha, f->phi, f->op);
+}
+
+static void
+drawtext(void *fp, int op)
+{
+ F_Image_text *f;
+ Font *font;
+ Point pt;
+ Image *s, *d;
+ String *str;
+ int locked;
+
+ f = fp;
+ if(f->dst == H || f->src == H)
+ goto Return;
+ if(f->font == H || f->str == H)
+ goto Return;
+ str = f->str;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ font = checkfont(f->font);
+ if(d->display!=s->display || d->display!=font->display)
+ return;
+ locked = lockdisplay(d->display);
+ if(str->len >= 0)
+ pt = stringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, op);
+ else
+ pt = runestringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+ Return:
+ P2P(*f->ret, pt);
+}
+
+void
+Image_text(void *fp)
+{
+ drawtext(fp, SoverD);
+}
+
+void
+Image_textop(void *fp)
+{
+ F_Image_textop *f;
+
+ f = fp;
+ drawtext(fp, f->op);
+}
+
+static void
+drawtextbg(void *fp, int op)
+{
+ F_Image_textbg *f;
+ Font *font;
+ Point pt;
+ Image *s, *d, *bg;
+ String *str;
+ int locked;
+
+ f = fp;
+ if(f->dst == H || f->src == H)
+ goto Return;
+ if(f->font == H || f->str == H)
+ goto Return;
+ str = f->str;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ bg = checkimage(f->bg);
+ font = checkfont(f->font);
+ if(d->display!=s->display || d->display!=font->display)
+ return;
+ locked = lockdisplay(d->display);
+ if(str->len >= 0)
+ pt = stringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, bg, IPOINT(f->bgp), op);
+ else
+ pt = runestringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, bg, IPOINT(f->bgp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+ Return:
+ P2P(*f->ret, pt);
+}
+
+void
+Image_textbg(void *fp)
+{
+ drawtextbg(fp, SoverD);
+}
+
+void
+Image_textbgop(void *fp)
+{
+ F_Image_textbgop *f;
+
+ f = fp;
+ drawtextbg(fp, f->op);
+}
+
+static void
+drawborder(void *fp, int op)
+{
+ F_Image_border *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display)
+ return;
+ locked = lockdisplay(d->display);
+ borderop(d, IRECT(f->r), f->i, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_border(void *fp)
+{
+ drawborder(fp, SoverD);
+}
+
+void
+Display_newimage(void *fp)
+{
+ F_Display_newimage *f;
+ Display *d;
+ int locked;
+
+ f = fp;
+ d = checkdisplay(f->d);
+ destroy(*f->ret);
+ *f->ret = H;
+ locked = lockdisplay(d);
+ *f->ret = allocdrawimage((DDisplay*)f->d, f->r, f->chans.desc,
+ nil, f->repl, f->color);
+ if(locked)
+ unlockdisplay(d);
+}
+
+void
+Display_colormix(void *fp)
+{
+ F_Display_colormix *f;
+ Display *disp;
+ Image *i;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+ locked = lockdisplay(disp);
+ i = allocimagemix(disp, f->c1, f->c2);
+ if(locked)
+ unlockdisplay(disp);
+ *f->ret = mkdrawimage(i, H, f->d, nil);
+}
+
+void
+Image_readpixels(void *fp)
+{
+ F_Image_readpixels *f;
+ Rectangle r;
+ Image *i;
+ int locked;
+
+ f = fp;
+ R2R(r, f->r);
+ i = checkimage(f->src);
+ locked = lockdisplay(i->display);
+ *f->ret = unloadimage(i, r, f->data->data, f->data->len);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_writepixels(void *fp)
+{
+ Rectangle r;
+ F_Image_writepixels *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ R2R(r, f->r);
+ i = checkimage(f->dst);
+ locked = lockdisplay(i->display);
+ *f->ret = loadimage(i, r, f->data->data, f->data->len);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_arrow(void *fp)
+{
+ F_Image_arrow *f;
+
+ f = fp;
+ *f->ret = ARROW(f->a, f->b, f->c);
+}
+
+void
+Image_name(void *fp)
+{
+ F_Image_name *f;
+ Image *i;
+ int locked, ok;
+ char *name;
+
+ f = fp;
+ *f->ret = -1;
+ i = checkimage(f->src);
+ name = string2c(f->name);
+ locked = lockdisplay(i->display);
+ *f->ret = ok = nameimage(i, name, f->in);
+ if(locked)
+ unlockdisplay(i->display);
+ if(ok){
+ destroy(f->src->iname);
+ if(f->in){
+ f->src->iname = f->name;
+ D2H(f->name)->ref++;
+ }else
+ f->src->iname = H;
+ }
+}
+
+Image*
+display_open(Display *disp, char *name)
+{
+ Image *i;
+ int fd;
+
+ fd = libopen(name, OREAD);
+ if(fd < 0)
+ return nil;
+
+ i = readimage(disp, fd, 1);
+ libclose(fd);
+ return i;
+}
+
+void
+Display_open(void *fp)
+{
+ Image *i;
+ Display *disp;
+ F_Display_open *f;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = lookupdisplay(f->d);
+ if(disp == nil)
+ return;
+ i = display_open(disp, string2c(f->name));
+ if(i == nil)
+ return;
+ *f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
+}
+
+void
+Display_namedimage(void *fp)
+{
+ F_Display_namedimage *f;
+ Display *d;
+ Image *i;
+ Draw_Image *di;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ d = checkdisplay(f->d);
+ locked = lockdisplay(d);
+ i = namedimage(d, string2c(f->name));
+ if(locked)
+ unlockdisplay(d);
+ if(i == nil)
+ return;
+ di = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, i->repl, 0);
+ *f->ret = di;
+ if(di == H){
+ locked = lockdisplay(d);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(d);
+ }else{
+ di->iname = f->name;
+ D2H(f->name)->ref++;
+ }
+}
+
+void
+Display_readimage(void *fp)
+{
+ Image *i;
+ Display *disp;
+ F_Display_readimage *f;
+ Sys_FD *fd;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ fd = f->fd;
+ if(fd == H)
+ return;
+ disp = checkdisplay(f->d);
+ i = readimage(disp, fd->fd, 1);
+ if(i == nil)
+ return;
+ *f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
+ if(*f->ret == H){
+ locked = lockdisplay(disp);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(disp);
+ }
+}
+
+void
+Display_writeimage(void *fp)
+{
+ Image *i;
+ F_Display_writeimage *f;
+ Sys_FD *fd;
+
+ f = fp;
+ *f->ret = -1;
+ fd = f->fd;
+ if(fd == H)
+ return;
+ i = checkimage(f->i);
+ if(checkdisplay(f->d) != i->display)
+ return;
+ *f->ret = writeimage(fd->fd, i, 1); /* TO DO: dolock? */
+}
+
+Draw_Screen*
+mkdrawscreen(Screen *s, Draw_Display *display)
+{
+ Heap *h;
+ DScreen *ds;
+ Draw_Image *dimage, *dfill;
+
+ dimage = mkdrawimage(s->image, H, display, nil);
+ dfill = mkdrawimage(s->fill, H, display, nil);
+ h = heap(TScreen);
+ if(h == H)
+ return nil;
+ ds = H2D(DScreen*, h);
+ ds->screen = s;
+ ds->drawscreen.fill = dfill;
+ D2H(dfill)->ref++;
+ ds->drawscreen.image = dimage;
+ D2H(dimage)->ref++;
+ ds->drawscreen.display = dimage->display;
+ D2H(dimage->display)->ref++;
+ ds->drawscreen.id = s->id;
+ ds->dref = s->display->limbo;
+ ds->dref->ref++;
+ return &ds->drawscreen;
+}
+
+static DScreen*
+allocdrawscreen(Draw_Image *dimage, Draw_Image *dfill, int public)
+{
+ Heap *h;
+ Screen *s;
+ DScreen *ds;
+ Image *image, *fill;
+
+ image = ((DImage*)dimage)->image;
+ fill = ((DImage*)dfill)->image;
+ s = allocscreen(image, fill, public);
+ if(s == 0)
+ return nil;
+ h = heap(TScreen);
+ if(h == H)
+ return nil;
+ ds = H2D(DScreen*, h);
+ ds->screen = s;
+ ds->drawscreen.fill = dfill;
+ D2H(dfill)->ref++;
+ ds->drawscreen.image = dimage;
+ D2H(dimage)->ref++;
+ ds->drawscreen.display = dimage->display;
+ D2H(dimage->display)->ref++;
+ ds->drawscreen.id = s->id;
+ ds->dref = image->display->limbo;
+ ds->dref->ref++;
+ return ds;
+}
+
+void
+Screen_allocate(void *fp)
+{
+ F_Screen_allocate *f;
+ DScreen *ds;
+ Image *image;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ image = checkimage(f->image);
+ checkimage(f->fill);
+ locked = lockdisplay(image->display);
+ ds = allocdrawscreen(f->image, f->fill, f->public);
+ if(ds != nil)
+ *f->ret = &ds->drawscreen;
+ if(locked)
+ unlockdisplay(image->display);
+}
+
+void
+Display_publicscreen(void *fp)
+{
+ F_Display_publicscreen *f;
+ Heap *h;
+ Screen *s;
+ DScreen *ds;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+ locked = lockdisplay(disp);
+ s = publicscreen(disp, f->id, disp->image->chan);
+ if(locked)
+ unlockdisplay(disp);
+ if(s == nil)
+ return;
+ h = heap(TScreen);
+ if(h == H)
+ return;
+ ds = H2D(DScreen*, h);
+ ds->screen = s;
+ ds->drawscreen.fill = H;
+ ds->drawscreen.image =H;
+ ds->drawscreen.id = s->id;
+ ds->drawscreen.display = f->d;
+ D2H(f->d)->ref++;
+ ds->dref = disp->limbo;
+ ds->dref->ref++;
+ *f->ret = &ds->drawscreen;
+}
+
+void
+freedrawscreen(Heap *h, int swept)
+{
+ DScreen *ds;
+ Screen *s;
+ Display *disp;
+ int locked;
+
+ ds = H2D(DScreen*, h);
+ if(!swept) {
+ destroy(ds->drawscreen.image);
+ destroy(ds->drawscreen.fill);
+ destroy(ds->drawscreen.display);
+ }
+ s = lookupscreen(&ds->drawscreen);
+ if(s == nil){
+ if(!swept)
+ freeptrs(ds, TScreen);
+ return;
+ }
+ disp = s->display;
+ locked = lockdisplay(disp);
+ freescreen(s);
+ if(locked)
+ unlockdisplay(disp);
+ display_dec(ds->dref);
+ /* screen header will be freed by caller */
+}
+
+void
+Font_build(void *fp)
+{
+ F_Font_build *f;
+ Font *font;
+ DFont *dfont;
+ Heap *h;
+ char buf[128];
+ char *name, *data;
+ Subfont *df;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+
+ name = string2c(f->name);
+ font = font_open(disp, name);
+ if(font == nil) {
+ if(strcmp(name, deffontname) == 0) {
+ df = disp->defaultsubfont;
+ sprint(buf, "%d %d\n0 %d\t%s\n",
+ df->height, df->ascent, df->n-1, name);
+ data = buf;
+ }
+ else
+ if(f->desc == H)
+ return;
+ else
+ data = string2c(f->desc);
+
+ locked = lockdisplay(disp);
+ font = buildfont(disp, data, name);
+ if(locked)
+ unlockdisplay(disp);
+ if(font == nil)
+ return;
+ }
+
+ h = heap(TFont);
+ if(h == H)
+ return;
+
+ dfont = H2D(DFont*, h);
+ dfont->font = font;
+ dfont->drawfont.name = f->name;
+ D2H(f->name)->ref++;
+ dfont->drawfont.height = font->height;
+ dfont->drawfont.ascent = font->ascent;
+ dfont->drawfont.display = f->d;
+ D2H(f->d)->ref++;
+ dfont->dref = disp->limbo;
+ dfont->dref->ref++;
+
+ *f->ret = &dfont->drawfont;
+}
+
+Font*
+font_open(Display *display, char *name)
+{
+ Cache *c;
+ Font *font;
+ int locked;
+
+ c = cachelookup(fcache, display, name);
+ if(c)
+ font = c->u.f;
+ else {
+ locked = lockdisplay(display);
+ font = openfont(display, name);
+ if(locked)
+ unlockdisplay(display);
+ if(font == nil)
+ return nil;
+ c = cacheinstall(fcache, display, name, font, "font");
+ }
+ if(c)
+ c->ref++;
+
+ return font;
+}
+
+void
+font_close(Font *f)
+{
+ Cache *c;
+ Display *disp;
+ int locked;
+ disp = f->display;
+ if(f->name == nil)
+ return;
+
+ /* fonts from Font_build() aren't always in fcache, but we still need to free them */
+ c = cachelookup(fcache, disp, f->name);
+ if(c != nil && f == c->u.f) {
+ if(c->ref <= 0)
+ return;
+ if(c->ref-- != 1)
+ return;
+ cacheuninstall(fcache, disp, f->name, "font");
+ }
+
+ locked = lockdisplay(disp);
+ freefont(f);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+freecachedsubfont(Subfont *sf)
+{
+ Cache *c;
+ Display *disp;
+
+ disp = sf->bits->display;
+ c = cachelookup(sfcache, disp, sf->name);
+ if(c == nil){
+ fprint(2, "subfont %s not cached\n", sf->name);
+ return;
+ }
+ if(c->ref > 0)
+ c->ref--;
+ /* if ref is zero, we leave it around for later harvesting by freeallsubfonts */
+}
+
+void
+freeallsubfonts(Display *d)
+{
+ int i;
+ Cache *c, *prev, *o;
+ Subfont *sf;
+ int locked;
+ if(cacheqlock == nil) /* may not have allocated anything yet */
+ return;
+ libqlock(cacheqlock);
+ for(i=0; i<BIHASH; i++){
+ c = sfcache[i];
+ prev = 0;
+ while(c != nil){
+ if(c->ref==0 && (d==nil || c->display==d)){
+ if(prev == 0)
+ sfcache[i] = c->next;
+ else
+ prev->next = c->next;
+ free(c->name);
+ sf = c->u.sf;
+ if(--sf->ref==0){
+ free(sf->info);
+ locked = lockdisplay(c->display);
+ freeimage(sf->bits);
+ if(locked)
+ unlockdisplay(c->display);
+ free(sf);
+ }
+ o = c;
+ c = c->next;
+ free(o);
+ }else{
+ prev = c;
+ c = c->next;
+ }
+ }
+ }
+ libqunlock(cacheqlock);
+}
+
+void
+subfont_close(Subfont *sf)
+{
+ freecachedsubfont(sf);
+}
+
+void
+freesubfont(Subfont *sf)
+{
+ freecachedsubfont(sf);
+}
+
+void
+Font_open(void *fp)
+{
+ Heap *h;
+ Font *font;
+ Display *disp;
+ DFont *df;
+ F_Font_open *f;
+
+ f = fp;
+
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+
+ font = font_open(disp, string2c(f->name));
+ if(font == 0)
+ return;
+
+ h = heap(TFont);
+ if(h == H)
+ return;
+
+ df = H2D(DFont*, h);
+ df->font = font;
+ df->drawfont.name = f->name;
+ D2H(f->name)->ref++;
+ df->drawfont.height = font->height;
+ df->drawfont.ascent = font->ascent;
+ df->drawfont.display = f->d;
+ D2H(f->d)->ref++;
+ df->dref = disp->limbo;
+ df->dref->ref++;
+ *f->ret = &df->drawfont;
+}
+
+void
+Font_width(void *fp)
+{
+ F_Font_width *f;
+ Font *font;
+ char *s;
+ int locked;
+
+ f = fp;
+ s = string2c(f->str);
+ if(f->f == H || s[0]=='\0')
+ *f->ret = 0;
+ else{
+ font = checkfont(f->f);
+ locked = lockdisplay(font->display);
+ *f->ret = stringwidth(font, s);
+ if(locked)
+ unlockdisplay(font->display);
+ }
+}
+
+void
+Font_bbox(void *fp)
+{
+ F_Font_bbox *f;
+ Draw_Rect *ret;
+
+ /* place holder for the real thing */
+ f = fp;
+ ret = f->ret;
+ ret->min.x = ret->min.y = 0;
+ ret->max.x = ret->max.y = 0;
+}
+
+/*
+ * BUG: would be nice if this cached the whole font.
+ * Instead only the subfonts are cached and the fonts are
+ * freed when released.
+ */
+void
+freedrawfont(Heap*h, int swept)
+{
+ Draw_Font *d;
+ Font *f;
+ d = H2D(Draw_Font*, h);
+ f = lookupfont(d);
+ if(!swept) {
+ destroy(d->name);
+ destroy(d->display);
+ }
+ font_close(f);
+ display_dec(((DFont*)d)->dref);
+}
+
+void
+Chans_text(void *fp)
+{
+ F_Chans_text *f;
+ char buf[16];
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ if(chantostr(buf, f->c.desc) != nil)
+ retstr(buf, f->ret);
+}
+
+void
+Chans_depth(void *fp)
+{
+ F_Chans_depth *f;
+
+ f = fp;
+ *f->ret = chantodepth(f->c.desc);
+}
+
+void
+Chans_eq(void *fp)
+{
+ F_Chans_eq *f;
+
+ f = fp;
+ *f->ret = f->c.desc == f->d.desc;
+}
+
+void
+Chans_mk(void *fp)
+{
+ F_Chans_mk *f;
+
+ f = fp;
+ f->ret->desc = strtochan(string2c(f->s));
+}
+
+void
+Display_rgb(void *fp)
+{
+ ulong c;
+ Display *disp;
+ F_Display_rgb *f;
+ int locked;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ disp = checkdisplay(f->d);
+
+ c = ((f->r&255)<<24)|((f->g&255)<<16)|((f->b&255)<<8)|0xFF;
+
+ locked = lockdisplay(disp);
+ *f->ret = color((DDisplay*)f->d, c);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Display_rgb2cmap(void *fp)
+{
+ F_Display_rgb2cmap *f;
+
+ f = fp;
+ /* f->display is unused, but someday may have color map */
+ *f->ret = rgb2cmap(f->r, f->g, f->b);
+}
+
+void
+Display_cmap2rgb(void *fp)
+{
+ F_Display_cmap2rgb *f;
+ ulong c;
+
+ f = fp;
+ /* f->display is unused, but someday may have color map */
+ c = cmap2rgb(f->c);
+ f->ret->t0 = (c>>16)&0xFF;
+ f->ret->t1 = (c>>8)&0xFF;
+ f->ret->t2 = (c>>0)&0xFF;
+}
+
+void
+Display_cmap2rgba(void *fp)
+{
+ F_Display_cmap2rgba *f;
+
+ f = fp;
+ /* f->display is unused, but someday may have color map */
+ *f->ret = cmap2rgba(f->c);
+}
+
+void
+Draw_setalpha(void *fp)
+{
+ F_Draw_setalpha *f;
+
+ f = fp;
+ *f->ret = setalpha(f->c, f->a);
+}
+
+void
+Draw_icossin(void *fp)
+{
+ F_Draw_icossin *f;
+ int s, c;
+
+ f = fp;
+ icossin(f->deg, &s, &c);
+ f->ret->t0 = s;
+ f->ret->t1 = c;
+}
+
+void
+Draw_icossin2(void *fp)
+{
+ F_Draw_icossin2 *f;
+ int s, c;
+
+ f = fp;
+ icossin2(f->p.x, f->p.y, &s, &c);
+ f->ret->t0 = s;
+ f->ret->t1 = c;
+}
+
+void
+Draw_bytesperline(void *fp)
+{
+ F_Draw_bytesperline *f;
+
+ f = fp;
+ *f->ret = bytesperline(IRECT(f->r), f->d);
+}
+
+Draw_Image*
+color(DDisplay *dd, ulong color)
+{
+ int c;
+ Draw_Rect r;
+
+ r.min.x = 0;
+ r.min.y = 0;
+ r.max.x = 1;
+ r.max.y = 1;
+ c = (color&0xff) == 0xff ? RGB24: RGBA32;
+ return allocdrawimage(dd, r, c, nil, 1, color);
+}
+
+Draw_Image*
+mkdrawimage(Image *i, Draw_Screen *screen, Draw_Display *display, void *ref)
+{
+ Heap *h;
+ DImage *di;
+
+ h = heap(TImage);
+ if(h == H)
+ return H;
+
+ di = H2D(DImage*, h);
+ di->image = i;
+ di->drawimage.screen = screen;
+ if(screen != H)
+ D2H(screen)->ref++;
+ di->drawimage.display = display;
+ if(display != H)
+ D2H(display)->ref++;
+ di->refreshptr = ref;
+
+ R2R(di->drawimage.r, i->r);
+ R2R(di->drawimage.clipr, i->clipr);
+ di->drawimage.chans.desc = i->chan;
+ di->drawimage.depth = i->depth;
+ di->drawimage.repl = i->repl;
+ di->flush = 1;
+ di->dref = i->display->limbo;
+ di->dref->ref++;
+ return &di->drawimage;
+}
+
+void
+Screen_newwindow(void *fp)
+{
+ F_Screen_newwindow *f;
+ Image *i;
+ Screen *s;
+ Rectangle r;
+ int locked;
+ void *v;
+
+ f = fp;
+ s = checkscreen(f->screen);
+ R2R(r, f->r);
+
+ if(f->backing != Refnone && f->backing != Refbackup)
+ f->backing = Refbackup;
+
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ locked = lockdisplay(s->display);
+ i = allocwindow(s, r, f->backing, f->color);
+ if(locked)
+ unlockdisplay(s->display);
+ if(i == nil)
+ return;
+
+ *f->ret = mkdrawimage(i, f->screen, f->screen->display, 0);
+}
+
+static
+void
+screentopbot(Draw_Screen *screen, Array *array, void (*topbot)(Image **, int))
+{
+ Screen *s;
+ Draw_Image **di;
+ Image **ip;
+ int i, n, locked;
+
+ s = checkscreen(screen);
+ di = (Draw_Image**)array->data;
+ ip = malloc(array->len * sizeof(Image*));
+ if(ip == nil)
+ return;
+ n = 0;
+ for(i=0; i<array->len; i++)
+ if(di[i] != H){
+ ip[n] = lookupimage(di[i]);
+ if(ip[n]==nil || ip[n]->screen != s){
+ free(ip);
+ return;
+ }
+ n++;
+ }
+ if(n == 0){
+ free(ip);
+ return;
+ }
+ locked = lockdisplay(s->display);
+ (*topbot)(ip, n);
+ free(ip);
+ flushimage(s->display, 1);
+ if(locked)
+ unlockdisplay(s->display);
+}
+
+void
+Screen_top(void *fp)
+{
+ F_Screen_top *f;
+ f = fp;
+ screentopbot(f->screen, f->wins, topnwindows);
+}
+
+void
+Screen_bottom(void *fp)
+{
+ F_Screen_top *f;
+ f = fp;
+ screentopbot(f->screen, f->wins, bottomnwindows);
+}
+
+void
+freedrawimage(Heap *h, int swept)
+{
+ Image *i;
+ int locked;
+ Display *disp;
+ Draw_Image *d;
+
+ d = H2D(Draw_Image*, h);
+ i = lookupimage(d);
+ if(i == nil) {
+ if(!swept)
+ freeptrs(d, TImage);
+ return;
+ }
+ disp = i->display;
+ locked = lockdisplay(disp);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(disp);
+ display_dec(((DImage*)d)->dref);
+ /* image/layer header will be freed by caller */
+}
+
+void
+Image_top(void *fp)
+{
+ F_Image_top *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ i = checkimage(f->win);
+ locked = lockdisplay(i->display);
+ topwindow(i);
+ flushimage(i->display, 1);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_origin(void *fp)
+{
+ F_Image_origin *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ i = checkimage(f->win);
+ locked = lockdisplay(i->display);
+ if(originwindow(i, IPOINT(f->log), IPOINT(f->scr)) < 0)
+ *f->ret = -1;
+ else{
+ f->win->r = DRECT(i->r);
+ f->win->clipr = DRECT(i->clipr);
+ *f->ret = 1;
+ }
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_bottom(void *fp)
+{
+ F_Image_top *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ i = checkimage(f->win);
+ locked = lockdisplay(i->display);
+ bottomwindow(i);
+ flushimage(i->display, 1);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+Draw_Image*
+allocdrawimage(DDisplay *ddisplay, Draw_Rect r, ulong chan, Image *iimage, int repl, int color)
+{
+ Heap *h;
+ DImage *di;
+ Rectangle rr;
+ Image *image;
+
+ image = iimage;
+ if(iimage == nil){
+ R2R(rr, r);
+ image = allocimage(ddisplay->display, rr, chan, repl, color);
+ if(image == nil)
+ return H;
+ }
+
+ h = heap(TImage);
+ if(h == H){
+ if(iimage == nil)
+ freeimage(image);
+ return H;
+ }
+
+ di = H2D(DImage*, h);
+ di->drawimage.r = r;
+ R2R(di->drawimage.clipr, image->clipr);
+ di->drawimage.chans.desc = chan;
+ di->drawimage.depth = chantodepth(chan);
+ di->drawimage.repl = repl;
+ di->drawimage.display = (Draw_Display*)ddisplay;
+ D2H(di->drawimage.display)->ref++;
+ di->drawimage.screen = H;
+ di->dref = ddisplay->display->limbo;
+ di->dref->ref++;
+ di->image = image;
+ di->refreshptr = 0;
+ di->flush = 1;
+
+ return &di->drawimage;
+}
+
+/*
+ * Entry points called from the draw library
+ */
+Subfont*
+lookupsubfont(Display *d, char *name)
+{
+ Cache *c;
+
+ c = cachelookup(sfcache, d, name);
+ if(c == nil)
+ return nil;
+ /*c->u.sf->ref++;*/ /* TO DO: need to revisit the reference counting */
+ return c->u.sf;
+}
+
+void
+installsubfont(char *name, Subfont *subfont)
+{
+ Cache *c;
+
+ c = cacheinstall(sfcache, subfont->bits->display, name, subfont, "subfont");
+ if(c)
+ c->ref++;
+}
+
+/*
+ * BUG version
+ */
+char*
+subfontname(char *cfname, char *fname, int maxdepth)
+{
+ char *t, *u, tmp1[256], tmp2[256];
+ int i, fd;
+
+ if(strcmp(cfname, deffontname) == 0)
+ return strdup(cfname);
+ t = cfname;
+ if(t[0] != '/'){
+ strcpy(tmp2, fname);
+ u = utfrrune(tmp2, '/');
+ if(u)
+ u[0] = 0;
+ else
+ strcpy(tmp2, ".");
+ snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t);
+ t = tmp1;
+ }
+
+ if(maxdepth > 8)
+ maxdepth = 8;
+
+ for(i=3; i>=0; i--){
+ if((1<<i) > maxdepth)
+ continue;
+ /* try i-bit grey */
+ snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
+ fd = libopen(tmp2, OREAD);
+ if(fd >= 0){
+ libclose(fd);
+ return strdup(tmp2);
+ }
+ }
+
+ return strdup(t);
+}
+
+void
+refreshslave(Display *d)
+{
+ int i, n, id;
+ uchar buf[5*(5*4)], *p;
+ Rectangle r;
+ Image *im;
+ int locked;
+
+ for(;;){
+ release();
+ n = kchanio(d->refchan, buf, sizeof buf, OREAD);
+ acquire();
+ if(n < 0) /* probably caused by closedisplay() closing refchan */
+ return; /* will fall off end of thread and close down */
+ locked = lockdisplay(d);
+ p = buf;
+ for(i=0; i<n; i+=5*4,p+=5*4){
+ id = BGLONG(p+0*4);
+ r.min.x = BGLONG(p+1*4);
+ r.min.y = BGLONG(p+2*4);
+ r.max.x = BGLONG(p+3*4);
+ r.max.y = BGLONG(p+4*4);
+ for(im=d->windows; im; im=im->next)
+ if(im->id == id)
+ break;
+ if(im && im->screen && im->reffn)
+ (*im->reffn)(im, r, im->refptr);
+ }
+ flushimage(d, 1);
+ if(locked)
+ unlockdisplay(d);
+ }
+}
+
+void
+startrefresh(Display *disp)
+{
+ USED(disp);
+}
+
+static
+int
+doflush(Display *d)
+{
+ int m, n;
+ char err[ERRMAX];
+ uchar *tp;
+
+ n = d->bufp-d->buf;
+ if(n <= 0)
+ return 1;
+
+ if(d->local == 0)
+ release();
+ if((m = kchanio(d->datachan, d->buf, n, OWRITE)) != n){
+ if(d->local == 0)
+ acquire();
+ kgerrstr(err, sizeof err);
+ if(_drawdebug || strcmp(err, "screen id in use") != 0 && strcmp(err, exImage) != 0){
+ print("flushimage fail: (%d not %d) d=%lux: %s\nbuffer: ", m, n, (ulong)d, err);
+ for(tp = d->buf; tp < d->bufp; tp++)
+ print("%.2x ", (int)*tp);
+ print("\n");
+ }
+ d->bufp = d->buf; /* might as well; chance of continuing */
+ return -1;
+ }
+ d->bufp = d->buf;
+ if(d->local == 0)
+ acquire();
+ return 1;
+}
+
+int
+flushimage(Display *d, int visible)
+{
+ int ret;
+ Refreshq *r;
+
+ for(;;){
+ if(visible)
+ *d->bufp++ = 'v'; /* one byte always reserved for this */
+ ret = doflush(d);
+ if(d->refhead == nil)
+ break;
+ while(r = d->refhead){ /* assign = */
+ d->refhead = r->next;
+ if(d->refhead == nil)
+ d->reftail = nil;
+ r->reffn(nil, r->r, r->refptr);
+ free(r);
+ }
+ }
+ return ret;
+}
+
+/*
+ * Turn off refresh for this window and remove any pending refresh events for it.
+ */
+void
+delrefresh(Image *i)
+{
+ Refreshq *r, *prev, *next;
+ int locked;
+ Display *d;
+ void *refptr;
+
+ d = i->display;
+ /*
+ * Any refresh function will do, because the data pointer is nil.
+ * Can't use nil, though, because that turns backing store back on.
+ */
+ if(d->local)
+ drawlsetrefresh(d->dataqid, i->id, memlnorefresh, nil);
+ refptr = i->refptr;
+ i->refptr = nil;
+ if(d->refhead==nil || refptr==nil)
+ return;
+ locked = lockdisplay(d);
+ prev = nil;
+ for(r=d->refhead; r; r=next){
+ next = r->next;
+ if(r->refptr == refptr){
+ if(prev)
+ prev->next = next;
+ else
+ d->refhead = next;
+ if(d->reftail == r)
+ d->reftail = prev;
+ free(r);
+ }else
+ prev = r;
+ }
+ if(locked)
+ unlockdisplay(d);
+}
+
+void
+queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr)
+{
+ Display *d;
+ Refreshq *rq;
+
+ d = i->display;
+ rq = malloc(sizeof(Refreshq));
+ if(rq == nil)
+ return;
+ if(d->reftail)
+ d->reftail->next = rq;
+ else
+ d->refhead = rq;
+ d->reftail = rq;
+ rq->reffn = reffn;
+ rq->refptr = refptr;
+ rq->r = r;
+}
+
+uchar*
+bufimage(Display *d, int n)
+{
+ uchar *p;
+
+ if(n<0 || n>Displaybufsize){
+ kwerrstr("bad count in bufimage");
+ return 0;
+ }
+ if(d->bufp+n > d->buf+Displaybufsize){
+ if(d->local==0 && currun()!=libqlowner(d->qlock)) {
+ print("bufimage: %lux %lux\n", (ulong)libqlowner(d->qlock), (ulong)currun());
+ abort();
+ }
+ if(doflush(d) < 0)
+ return 0;
+ }
+ p = d->bufp;
+ d->bufp += n;
+ /* return with buffer locked */
+ return p;
+}
+
+void
+drawerror(Display *d, char *s)
+{
+ USED(d);
+ fprint(2, "draw: %s: %r\n", s);
+}
diff --git a/libinterp/drawmod.h b/libinterp/drawmod.h
new file mode 100644
index 00000000..f69eea95
--- /dev/null
+++ b/libinterp/drawmod.h
@@ -0,0 +1,94 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Drawmodtab[]={
+ "Rect.Xrect",0xd1fbcdc0,Rect_Xrect,64,0,{0},
+ "Point.add",0x95a87a7,Point_add,48,0,{0},
+ "Rect.addpt",0xbcba91ad,Rect_addpt,56,0,{0},
+ "Display.allocate",0x74694470,Display_allocate,40,2,{0x0,0x80,},
+ "Screen.allocate",0x1e813b8a,Screen_allocate,48,2,{0x0,0xc0,},
+ "Image.arc",0x1685a04e,Image_arc,80,2,{0x0,0x82,},
+ "Image.arcop",0x8521de24,Image_arcop,80,2,{0x0,0x82,},
+ "Image.arrow",0x7b3fc6d3,Image_arrow,48,0,{0},
+ "Font.bbox",0x541e2d08,Font_bbox,40,2,{0x0,0xc0,},
+ "Image.bezier",0x5baca124,Image_bezier,96,3,{0x0,0x80,0x8,},
+ "Image.bezierop",0xae13ba0e,Image_bezierop,96,3,{0x0,0x80,0x8,},
+ "Image.bezspline",0x70f06194,Image_bezspline,64,2,{0x0,0xc4,},
+ "Image.bezsplineop",0x94b3bea1,Image_bezsplineop,72,2,{0x0,0xc4,},
+ "Image.border",0x59381f67,Image_border,72,2,{0x0,0x82,},
+ "Image.bottom",0x642fa8b1,Image_bottom,40,2,{0x0,0x80,},
+ "Screen.bottom",0xe2817b5f,Screen_bottom,40,2,{0x0,0xc0,},
+ "Font.build",0x7fddba2c,Font_build,48,2,{0x0,0xe0,},
+ "bytesperline",0xab1724b2,Draw_bytesperline,56,0,{0},
+ "Rect.canon",0xe969971c,Rect_canon,48,0,{0},
+ "Rect.clip",0x1ad68a89,Rect_clip,64,0,{0},
+ "Display.cmap2rgb",0xda836903,Display_cmap2rgb,40,2,{0x0,0x80,},
+ "Display.cmap2rgba",0xa64b341,Display_cmap2rgba,40,2,{0x0,0x80,},
+ "Display.color",0xac54c4aa,Display_color,40,2,{0x0,0x80,},
+ "Display.colormix",0x9e941050,Display_colormix,48,2,{0x0,0x80,},
+ "Rect.combine",0x35d786ac,Rect_combine,64,0,{0},
+ "Rect.contains",0x5f13af31,Rect_contains,56,0,{0},
+ "Chans.depth",0x90b71a6,Chans_depth,40,0,{0},
+ "Point.div",0x7f0ac44e,Point_div,48,0,{0},
+ "Image.draw",0xe2951762,Image_draw,72,2,{0x0,0x86,},
+ "Image.drawop",0x7e2751d3,Image_drawop,72,2,{0x0,0x86,},
+ "Rect.dx",0x8db540cc,Rect_dx,48,0,{0},
+ "Rect.dy",0x8db540cc,Rect_dy,48,0,{0},
+ "Image.ellipse",0xea6f2000,Image_ellipse,72,2,{0x0,0x82,},
+ "Image.ellipseop",0xc0af34c6,Image_ellipseop,72,2,{0x0,0x82,},
+ "Chans.eq",0x2ba41fd4,Chans_eq,40,0,{0},
+ "Point.eq",0xd0634e59,Point_eq,48,0,{0},
+ "Rect.eq",0xd1fbcdc0,Rect_eq,64,0,{0},
+ "Image.fillarc",0x784ac6f8,Image_fillarc,72,2,{0x0,0x84,},
+ "Image.fillarcop",0xbbcdbdd,Image_fillarcop,80,2,{0x0,0x84,},
+ "Image.fillbezier",0x4a07ed44,Image_fillbezier,88,3,{0x0,0x80,0x20,},
+ "Image.fillbezierop",0xb3796aa0,Image_fillbezierop,88,3,{0x0,0x80,0x20,},
+ "Image.fillbezspline",0x4aac99aa,Image_fillbezspline,56,2,{0x0,0xd0,},
+ "Image.fillbezsplineop",0x6288a256,Image_fillbezsplineop,64,2,{0x0,0xd0,},
+ "Image.fillellipse",0xc2961c2b,Image_fillellipse,64,2,{0x0,0x84,},
+ "Image.fillellipseop",0x9816222d,Image_fillellipseop,72,2,{0x0,0x84,},
+ "Image.fillpoly",0x4aac99aa,Image_fillpoly,56,2,{0x0,0xd0,},
+ "Image.fillpolyop",0x6288a256,Image_fillpolyop,64,2,{0x0,0xd0,},
+ "Image.flush",0xb09fc26e,Image_flush,40,2,{0x0,0x80,},
+ "Image.gendraw",0xa30a11c7,Image_gendraw,80,3,{0x0,0x84,0x80,},
+ "Image.gendrawop",0x3e8228a,Image_gendrawop,80,3,{0x0,0x84,0x80,},
+ "Display.getwindow",0xdfbf1d73,Display_getwindow,56,2,{0x0,0xf0,},
+ "icossin",0x10ea0ce,Draw_icossin,40,0,{0},
+ "icossin2",0xd07585f7,Draw_icossin2,40,0,{0},
+ "Point.in",0xcf69adf9,Point_in,56,0,{0},
+ "Rect.inrect",0xd1fbcdc0,Rect_inrect,64,0,{0},
+ "Rect.inset",0x1fabb24,Rect_inset,56,0,{0},
+ "Image.line",0x7288c7b9,Image_line,80,3,{0x0,0x80,0x80,},
+ "Image.lineop",0xe34363b9,Image_lineop,80,3,{0x0,0x80,0x80,},
+ "Chans.mk",0xadae6aad,Chans_mk,40,2,{0x0,0x80,},
+ "Point.mul",0x7f0ac44e,Point_mul,48,0,{0},
+ "Image.name",0xdff53107,Image_name,48,2,{0x0,0xc0,},
+ "Display.namedimage",0x47522dfe,Display_namedimage,40,2,{0x0,0xc0,},
+ "Display.newimage",0xb8479988,Display_newimage,64,2,{0x0,0x80,},
+ "Screen.newwindow",0xcf19f7a8,Screen_newwindow,64,2,{0x0,0x80,},
+ "Display.open",0x47522dfe,Display_open,40,2,{0x0,0xc0,},
+ "Font.open",0xddcb2ff0,Font_open,40,2,{0x0,0xc0,},
+ "Image.origin",0x9171b0bd,Image_origin,56,2,{0x0,0x80,},
+ "Image.poly",0x70f06194,Image_poly,64,2,{0x0,0xc4,},
+ "Image.polyop",0x94b3bea1,Image_polyop,72,2,{0x0,0xc4,},
+ "Display.publicscreen",0x507e0780,Display_publicscreen,40,2,{0x0,0x80,},
+ "Display.readimage",0xd38f4d48,Display_readimage,40,2,{0x0,0xc0,},
+ "Image.readpixels",0x93d30c7c,Image_readpixels,56,2,{0x0,0x84,},
+ "Display.rgb",0x8e71a513,Display_rgb,48,2,{0x0,0x80,},
+ "Display.rgb2cmap",0xbf6c3d95,Display_rgb2cmap,48,2,{0x0,0x80,},
+ "setalpha",0x6584767b,Draw_setalpha,40,0,{0},
+ "Rect.size",0x3ecfd83e,Rect_size,48,0,{0},
+ "Display.startrefresh",0xf0df9cae,Display_startrefresh,40,2,{0x0,0x80,},
+ "Point.sub",0x95a87a7,Point_sub,48,0,{0},
+ "Rect.subpt",0xbcba91ad,Rect_subpt,56,0,{0},
+ "Chans.text",0xb20b7b7b,Chans_text,40,0,{0},
+ "Image.text",0xa5927686,Image_text,64,2,{0x0,0x93,},
+ "Image.textbg",0xbbb55403,Image_textbg,80,3,{0x0,0x93,0x80,},
+ "Image.textbgop",0xea84ed21,Image_textbgop,80,3,{0x0,0x93,0x80,},
+ "Image.textop",0x22b71b43,Image_textop,72,2,{0x0,0x93,},
+ "Image.top",0x642fa8b1,Image_top,40,2,{0x0,0x80,},
+ "Screen.top",0xe2817b5f,Screen_top,40,2,{0x0,0xc0,},
+ "Font.width",0x1c70cba4,Font_width,40,2,{0x0,0xc0,},
+ "Display.writeimage",0x7bd53940,Display_writeimage,48,2,{0x0,0xe0,},
+ "Image.writepixels",0x93d30c7c,Image_writepixels,56,2,{0x0,0x84,},
+ 0
+};
+#define Drawmodlen 89
diff --git a/libinterp/freetype.c b/libinterp/freetype.c
new file mode 100644
index 00000000..860b119d
--- /dev/null
+++ b/libinterp/freetype.c
@@ -0,0 +1,231 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "freetypemod.h"
+#include "freetype.h"
+
+
+typedef struct Face Face;
+struct Face {
+ Freetype_Face freetypeface; /* limbo part */
+ FTface ftface; /* private parts */
+};
+
+Type* TMatrix;
+Type* TVector;
+Type* TFace;
+Type* TGlyph;
+
+static uchar Matrixmap[] = Freetype_Matrix_map;
+static uchar Vectormap[] = Freetype_Vector_map;
+static uchar Facemap[] = Freetype_Face_map;
+static uchar Glyphmap[] = Freetype_Glyph_map;
+
+static void freeface(Heap*, int);
+static Face* ckface(Freetype_Face*);
+
+void
+freetypemodinit(void)
+{
+ builtinmod("$Freetype", Freetypemodtab, Freetypemodlen);
+ TMatrix = dtype(freeheap, sizeof(Freetype_Matrix), Matrixmap, sizeof(Matrixmap));
+ TVector = dtype(freeheap, sizeof(Freetype_Vector), Vectormap, sizeof(Vectormap));
+ TFace = dtype(freeface, sizeof(Face), Facemap, sizeof(Facemap));
+ TGlyph = dtype(freeheap, sizeof(Freetype_Glyph), Glyphmap, sizeof(Glyphmap));
+}
+
+void
+Face_haschar(void *fp)
+{
+ F_Face_haschar *f = fp;
+ Face *face;
+
+ *f->ret = 0;
+ face = ckface(f->face);
+ release();
+ *f->ret = fthaschar(face->ftface, f->c);
+ acquire();
+}
+
+void
+Face_loadglyph(void *fp)
+{
+ F_Face_loadglyph *f = fp;
+ Heap *h;
+ Face *face;
+ Freetype_Glyph *g;
+ FTglyph ftg;
+ int n, i, s1bpr, s2bpr;
+ char *err;
+
+ face = ckface(f->face);
+
+ destroy(*f->ret);
+ *f->ret = H;
+
+ release();
+ err = ftloadglyph(face->ftface, f->c, &ftg);
+ acquire();
+ if (err != nil) {
+ kwerrstr(err);
+ return;
+ }
+
+ h = heap(TGlyph);
+ if (h == H) {
+ kwerrstr(exNomem);
+ return;
+ }
+ g = H2D(Freetype_Glyph*, h);
+ n = ftg.width*ftg.height;
+ h = heaparray(&Tbyte, n);
+ if (h == H) {
+ destroy(g);
+ kwerrstr(exNomem);
+ return;
+ }
+ g->bitmap = H2D(Array*, h);
+ g->top = ftg.top;
+ g->left = ftg.left;
+ g->height = ftg.height;
+ g->width = ftg.width;
+ g->advance.x = ftg.advx;
+ g->advance.y = ftg.advy;
+
+ s1bpr = ftg.width;
+ s2bpr = ftg.bpr;
+ for (i = 0; i < ftg.height; i++)
+ memcpy(g->bitmap->data+(i*s1bpr), ftg.bitmap+(i*s2bpr), s1bpr);
+ *f->ret = g;
+}
+
+void
+Freetype_newface(void *fp)
+{
+ F_Freetype_newface *f = fp;
+ Heap *h;
+ Face *face;
+ Freetype_Face *limboface;
+ FTfaceinfo finfo;
+ char *path;
+ char *err;
+
+ destroy(*f->ret);
+ *f->ret = H;
+
+ h = heapz(TFace);
+ if (h == H) {
+ kwerrstr(exNomem);
+ return;
+ }
+
+ face = H2D(Face*, h);
+ limboface = (Freetype_Face*)face;
+ *f->ret = limboface;
+ path = strdup(string2c(f->path)); /* string2c() can call error() */
+ release();
+ err = ftnewface(path, f->index, &face->ftface, &finfo);
+ acquire();
+ free(path);
+ if (err != nil) {
+ *f->ret = H;
+ destroy(face);
+ kwerrstr(err);
+ return;
+ }
+ limboface->nfaces = finfo.nfaces;
+ limboface->index = finfo.index;
+ limboface->style = finfo.style;
+ limboface->height = finfo.height;
+ limboface->ascent = finfo.ascent;
+ limboface->familyname = c2string(finfo.familyname, strlen(finfo.familyname));
+ limboface->stylename = c2string(finfo.stylename, strlen(finfo.stylename));
+ *f->ret = limboface;
+}
+
+void
+Freetype_newmemface(void *fp)
+{
+ F_Freetype_newmemface *f = fp;
+
+ destroy(*f->ret);
+ *f->ret = H;
+
+ kwerrstr("not implemented");
+}
+
+void
+Face_setcharsize(void *fp)
+{
+ F_Face_setcharsize *f = fp;
+ Face *face;
+ Freetype_Face *limboface;
+ FTfaceinfo finfo;
+ char *err;
+
+ face = ckface(f->face);
+ limboface = (Freetype_Face*)face;
+ release();
+ err = ftsetcharsize(face->ftface, f->pts, f->hdpi, f->vdpi, &finfo);
+ acquire();
+ if (err == nil) {
+ limboface->height = finfo.height;
+ limboface->ascent = finfo.ascent;
+ }
+ retstr(err, f->ret);
+}
+
+void
+Face_settransform(void *fp)
+{
+ F_Face_settransform *f = fp;
+ FTmatrix *m = nil;
+ FTvector *v = nil;
+ Face *face;
+
+ face = ckface(f->face);
+
+ /*
+ * ftsettransform() has no error return
+ * we have one for consistency - but always nil for now
+ */
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if (f->m != H)
+ m = (FTmatrix*)(f->m);
+ if (f->v != H)
+ v = (FTvector*)(f->v);
+ release();
+ ftsettransform(face->ftface, m, v);
+ acquire();
+}
+
+static void
+freeface(Heap *h, int swept)
+{
+ Face *face = H2D(Face*, h);
+
+ if (!swept) {
+ destroy(face->freetypeface.familyname);
+ destroy(face->freetypeface.stylename);
+ }
+ release();
+ ftdoneface(face->ftface);
+ acquire();
+ memset(&face->ftface, 0, sizeof(face->ftface));
+}
+
+static Face*
+ckface(Freetype_Face *face)
+{
+ if (face == nil || face == H)
+ error("nil Face");
+ if (D2H(face)->t != TFace)
+ error(exType);
+ return (Face*)face;
+}
+
diff --git a/libinterp/freetypemod.h b/libinterp/freetypemod.h
new file mode 100644
index 00000000..eba89bef
--- /dev/null
+++ b/libinterp/freetypemod.h
@@ -0,0 +1,11 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Freetypemodtab[]={
+ "Face.haschar",0x6a7da190,Face_haschar,40,2,{0x0,0x80,},
+ "Face.loadglyph",0xdd275b67,Face_loadglyph,40,2,{0x0,0x80,},
+ "newface",0x18a90be,Freetype_newface,40,2,{0x0,0x80,},
+ "newmemface",0xc56f82dd,Freetype_newmemface,40,2,{0x0,0x80,},
+ "Face.setcharsize",0xb282ce87,Face_setcharsize,48,2,{0x0,0x80,},
+ "Face.settransform",0xcf26b85e,Face_settransform,48,2,{0x0,0xe0,},
+ 0
+};
+#define Freetypemodlen 6
diff --git a/libinterp/gc.c b/libinterp/gc.c
new file mode 100644
index 00000000..fd748af8
--- /dev/null
+++ b/libinterp/gc.c
@@ -0,0 +1,383 @@
+#include "lib9.h"
+#include "interp.h"
+#include "pool.h"
+
+enum
+{
+ Quanta = 50, /* Allocated blocks to sweep each time slice usually */
+ MaxQuanta = 15*Quanta,
+ PTRHASH = (1<<5)
+};
+
+static int quanta = Quanta;
+static int gce, gct = 1;
+
+typedef struct Ptrhash Ptrhash;
+struct Ptrhash
+{
+ Heap *value;
+ Ptrhash *next;
+};
+
+ int nprop;
+ int gchalt;
+ int mflag;
+ int mutator = 0;
+ int gccolor = 3;
+
+ ulong gcnruns;
+ ulong gcsweeps;
+ ulong gcbroken;
+ ulong gchalted;
+ ulong gcepochs;
+ uvlong gcdestroys;
+ uvlong gcinspects;
+
+static int marker = 1;
+static int sweeper = 2;
+static Bhdr* base;
+static Bhdr* limit;
+Bhdr* ptr;
+static int visit;
+extern Pool* heapmem;
+static Ptrhash *ptrtab[PTRHASH];
+static Ptrhash *ptrfree;
+
+#define HASHPTR(p) (((ulong)(p) >> 6) & (PTRHASH - 1))
+
+void
+ptradd(Heap *v)
+{
+ int h;
+ Ptrhash *p;
+
+ if ((p = ptrfree) != nil)
+ ptrfree = p->next;
+ else if ((p = malloc(sizeof (Ptrhash))) == nil)
+ error("ptradd malloc");
+ h = HASHPTR(v);
+ p->value = v;
+ p->next = ptrtab[h];
+ ptrtab[h] = p;
+}
+
+void
+ptrdel(Heap *v)
+{
+ Ptrhash *p, **l;
+
+ for (l = &ptrtab[HASHPTR(v)]; (p = *l) != nil; l = &p->next) {
+ if (p->value == v) {
+ *l = p->next;
+ p->next = ptrfree;
+ ptrfree = p;
+ return;
+ }
+ }
+ /* ptradd must have failed */
+}
+
+static void
+ptrmark(void)
+{
+ int i;
+ Heap *h;
+ Ptrhash *p;
+
+ for (i = 0; i < PTRHASH; i++) {
+ for (p = ptrtab[i]; p != nil; p = p->next) {
+ h = p->value;
+ Setmark(h);
+ }
+ }
+}
+
+void
+noptrs(Type *t, void *vw)
+{
+ USED(t);
+ USED(vw);
+}
+
+static int markdepth;
+
+/* code simpler with a depth search compared to a width search*/
+void
+markheap(Type *t, void *vw)
+{
+ Heap *h;
+ uchar *p;
+ int i, c, m;
+ WORD **w, **q;
+ Type *t1;
+
+ if(t == nil || t->np == 0)
+ return;
+
+ markdepth++;
+ w = (WORD**)vw;
+ p = t->map;
+ for(i = 0; i < t->np; i++) {
+ c = *p++;
+ if(c != 0) {
+ q = w;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if((c & m) && *q != H) {
+ h = D2H(*q);
+ Setmark(h);
+ if(h->color == propagator && --visit >= 0 && markdepth < 64){
+ gce--;
+ h->color = mutator;
+ if((t1 = h->t) != nil)
+ t1->mark(t1, H2D(void*, h));
+ }
+ }
+ q++;
+ }
+ }
+ w += 8;
+ }
+ markdepth--;
+}
+
+/*
+ * This routine should be modified to be incremental, but how?
+ */
+void
+markarray(Type *t, void *vw)
+{
+ int i;
+ Heap *h;
+ uchar *v;
+ Array *a;
+
+ USED(t);
+
+ a = vw;
+ t = a->t;
+ if(a->root != H) {
+ h = D2H(a->root);
+ Setmark(h);
+ }
+
+ if(t->np == 0)
+ return;
+
+ v = a->data;
+ for(i = 0; i < a->len; i++) {
+ markheap(t, v);
+ v += t->size;
+ }
+ visit -= a->len;
+}
+
+void
+marklist(Type *t, void *vw)
+{
+ List *l;
+ Heap *h;
+
+ USED(t);
+ l = vw;
+ markheap(l->t, l->data);
+ while(visit > 0) {
+ l = l->tail;
+ if(l == H)
+ return;
+ h = D2H(l);
+ Setmark(h);
+ markheap(l->t, l->data);
+ visit--;
+ }
+ l = l->tail;
+ if(l != H) {
+ D2H(l)->color = propagator;
+ nprop = 1;
+ }
+}
+
+static void
+rootset(Prog *root)
+{
+ Heap *h;
+ Type *t;
+ Frame *f;
+ Module *m;
+ Stkext *sx;
+ Modlink *ml;
+ uchar *fp, *sp, *ex, *mp;
+
+ mutator = gccolor % 3;
+ marker = (gccolor-1)%3;
+ sweeper = (gccolor-2)%3;
+
+ while(root != nil) {
+ ml = root->R.M;
+ h = D2H(ml);
+ Setmark(h);
+ mp = ml->MP;
+ if(mp != H) {
+ h = D2H(mp);
+ Setmark(h);
+ }
+
+ sp = root->R.SP;
+ ex = root->R.EX;
+ while(ex != nil) {
+ sx = (Stkext*)ex;
+ fp = sx->reg.tos.fu;
+ while(fp != sp) {
+ f = (Frame*)fp;
+ t = f->t;
+ if(t == nil)
+ t = sx->reg.TR;
+ fp += t->size;
+ t->mark(t, f);
+ ml = f->mr;
+ if(ml != nil) {
+ h = D2H(ml);
+ Setmark(h);
+ mp = ml->MP;
+ if(mp != H) {
+ h = D2H(mp);
+ Setmark(h);
+ }
+ }
+ }
+ ex = sx->reg.EX;
+ sp = sx->reg.SP;
+ }
+
+ root = root->next;
+ }
+
+ for(m = modules; m != nil; m = m->link) {
+ if(m->origmp != H) {
+ h = D2H(m->origmp);
+ Setmark(h);
+ }
+ }
+
+ ptrmark();
+}
+
+static int
+okbhdr(Bhdr *b)
+{
+ if(b == nil)
+ return 0;
+ switch(b->magic) {
+ case MAGIC_A:
+ case MAGIC_F:
+ case MAGIC_E:
+ case MAGIC_I:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+domflag(Heap *h)
+{
+ int i;
+ Module *m;
+
+ print("sweep h=0x%lux t=0x%lux c=%d", (ulong)h, (ulong)h->t, h->color);
+ for(m = modules; m != nil; m = m->link) {
+ for(i = 0; i < m->ntype; i++) {
+ if(m->type[i] == h->t) {
+ print(" module %s desc %d", m->name, i);
+ break;
+ }
+ }
+ }
+ print("\n");
+ if(mflag > 1)
+ abort();
+}
+
+void
+rungc(Prog *p)
+{
+ Type *t;
+ Heap *h;
+ Bhdr *b;
+
+ gcnruns++;
+ if(gchalt) {
+ gchalted++;
+ return;
+ }
+ if(base == nil) {
+ gcsweeps++;
+ b = poolchain(heapmem);
+ base = b;
+ ptr = b;
+ limit = B2LIMIT(b);
+ }
+
+ /* Chain broken ? */
+ if(!okbhdr(ptr)) {
+ base = nil;
+ gcbroken++;
+ return;
+ }
+
+ for(visit = quanta; visit > 0; ) {
+ if(ptr->magic == MAGIC_A) {
+ visit--;
+ gct++;
+ gcinspects++;
+ h = B2D(ptr);
+ t = h->t;
+ if(h->color == propagator) {
+ gce--;
+ h->color = mutator;
+ if(t != nil)
+ t->mark(t, H2D(void*, h));
+ }
+ else
+ if(h->color == sweeper) {
+ gce++;
+ if(0 && mflag)
+ domflag(h);
+ if(heapmonitor != nil)
+ heapmonitor(2, h, 0);
+ if(t != nil) {
+ gclock();
+ t->free(h, 1);
+ gcunlock();
+ freetype(t);
+ }
+ gcdestroys++;
+ poolfree(heapmem, h);
+ }
+ }
+ ptr = B2NB(ptr);
+ if(ptr >= limit) {
+ base = base->clink;
+ if(base == nil)
+ break;
+ ptr = base;
+ limit = B2LIMIT(base);
+ }
+ }
+
+ quanta = (MaxQuanta+Quanta)/2 + ((MaxQuanta-Quanta)/20)*((100*gce)/gct);
+ if(quanta < Quanta)
+ quanta = Quanta;
+ if(quanta > MaxQuanta)
+ quanta = MaxQuanta;
+
+ if(base != nil) /* Completed this iteration ? */
+ return;
+ if(nprop == 0) { /* Completed the epoch ? */
+ gcepochs++;
+ gccolor++;
+ rootset(p);
+ gce = 0;
+ gct = 1;
+ return;
+ }
+ nprop = 0;
+}
diff --git a/libinterp/geom.c b/libinterp/geom.c
new file mode 100644
index 00000000..55a2c4cc
--- /dev/null
+++ b/libinterp/geom.c
@@ -0,0 +1,309 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "draw.h"
+#include "runt.h"
+#include "raise.h"
+
+void
+Point_add(void *fp)
+{
+ F_Point_add *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->p.x + f->q.x;
+ ret->y = f->p.y + f->q.y;
+}
+
+void
+Point_sub(void *fp)
+{
+ F_Point_sub *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->p.x - f->q.x;
+ ret->y = f->p.y - f->q.y;
+}
+
+void
+Point_mul(void *fp)
+{
+ F_Point_mul *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->p.x * f->i;
+ ret->y = f->p.y * f->i;
+}
+
+void
+Point_div(void *fp)
+{
+ F_Point_div *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ if(f->i == 0)
+ error(exZdiv);
+ ret = f->ret;
+ ret->x = f->p.x / f->i;
+ ret->y = f->p.y / f->i;
+}
+
+void
+Point_eq(void *fp)
+{
+ F_Point_eq *f;
+
+ f = fp;
+ *f->ret = f->p.x == f->q.x && f->p.y == f->q.y;
+}
+
+void
+Point_in(void *fp)
+{
+ F_Point_in *f;
+
+ f = fp;
+ *f->ret = f->p.x >= f->r.min.x && f->p.x < f->r.max.x &&
+ f->p.y >= f->r.min.y && f->p.y < f->r.max.y;
+}
+
+void
+Rect_canon(void *fp)
+{
+ F_Rect_canon *f;
+ Draw_Rect *ret;
+ WORD t;
+
+ f = fp;
+
+ ret = f->ret;
+ if(f->r.max.x < f->r.min.x){
+ t = f->r.max.x;
+ ret->max.x = f->r.min.x;
+ ret->min.x = t;
+ }else{
+ t = f->r.max.x;
+ ret->min.x = f->r.min.x;
+ ret->max.x = t;
+ }
+ if(f->r.max.y < f->r.min.y){
+ t = f->r.max.y;
+ ret->max.y = f->r.min.y;
+ ret->min.y = t;
+ }else{
+ t = f->r.max.y;
+ ret->min.y = f->r.min.y;
+ ret->max.y = t;
+ }
+}
+
+void
+Rect_combine(void *fp)
+{
+ F_Rect_combine *f;
+ Draw_Rect *ret;
+
+ f = fp;
+ ret = f->ret;
+ *ret = f->r;
+ if(f->r.min.x > f->s.min.x)
+ ret->min.x = f->s.min.x;
+ if(f->r.min.y > f->s.min.y)
+ ret->min.y = f->s.min.y;
+ if(f->r.max.x < f->s.max.x)
+ ret->max.x = f->s.max.x;
+ if(f->r.max.y < f->s.max.y)
+ ret->max.y = f->s.max.y;
+}
+
+void
+Rect_eq(void *fp)
+{
+ F_Rect_eq *f;
+
+ f = fp;
+
+ *f->ret = f->r.min.x == f->s.min.x
+ && f->r.max.x == f->s.max.x
+ && f->r.min.y == f->s.min.y
+ && f->r.max.y == f->s.max.y;
+}
+
+void
+Rect_Xrect(void *fp)
+{
+ F_Rect_Xrect *f;
+
+ f = fp;
+
+ *f->ret = f->r.min.x < f->s.max.x
+ && f->s.min.x < f->r.max.x
+ && f->r.min.y < f->s.max.y
+ && f->s.min.y < f->r.max.y;
+}
+
+void
+Rect_clip(void *fp)
+{
+ F_Rect_clip *f;
+ Draw_Rect *r, *s, *ret;
+
+ f = fp;
+
+ r = &f->r;
+ s = &f->s;
+ ret = &f->ret->t0;
+
+ /*
+ * Expand rectXrect() in line for speed
+ */
+ if(!(r->min.x<s->max.x && s->min.x<r->max.x
+ && r->min.y<s->max.y && s->min.y<r->max.y)){
+ *ret = *r;
+ f->ret->t1 = 0;
+ return;
+ }
+
+ /* They must overlap */
+ if(r->min.x < s->min.x)
+ ret->min.x = s->min.x;
+ else
+ ret->min.x = r->min.x;
+ if(r->min.y < s->min.y)
+ ret->min.y = s->min.y;
+ else
+ ret->min.y = r->min.y;
+ if(r->max.x > s->max.x)
+ ret->max.x = s->max.x;
+ else
+ ret->max.x = r->max.x;
+ if(r->max.y > s->max.y)
+ ret->max.y = s->max.y;
+ else
+ ret->max.y = r->max.y;
+ f->ret->t1 = 1;
+}
+
+void
+Rect_inrect(void *fp)
+{
+ F_Rect_inrect *f;
+
+ f = fp;
+
+ *f->ret = f->s.min.x <= f->r.min.x
+ && f->r.max.x <= f->s.max.x
+ && f->s.min.y <= f->r.min.y
+ && f->r.max.y <= f->s.max.y;
+}
+
+void
+Rect_contains(void *fp)
+{
+ F_Rect_contains *f;
+ WORD x, y;
+
+ f = fp;
+
+ x = f->p.x;
+ y = f->p.y;
+ *f->ret = x >= f->r.min.x && x < f->r.max.x
+ && y >= f->r.min.y && y < f->r.max.y;
+}
+
+void
+Rect_addpt(void *fp)
+{
+ F_Rect_addpt *f;
+ Draw_Rect *ret;
+ WORD n;
+
+ f = fp;
+
+ ret = f->ret;
+ n = f->p.x;
+ ret->min.x = f->r.min.x + n;
+ ret->max.x = f->r.max.x + n;
+ n = f->p.y;
+ ret->min.y = f->r.min.y + n;
+ ret->max.y = f->r.max.y + n;
+}
+
+void
+Rect_subpt(void *fp)
+{
+ WORD n;
+ F_Rect_subpt *f;
+ Draw_Rect *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ n = f->p.x;
+ ret->min.x = f->r.min.x - n;
+ ret->max.x = f->r.max.x - n;
+ n = f->p.y;
+ ret->min.y = f->r.min.y - n;
+ ret->max.y = f->r.max.y - n;
+}
+
+void
+Rect_inset(void *fp)
+{
+ WORD n;
+ Draw_Rect *ret;
+ F_Rect_inset *f;
+
+ f = fp;
+
+ ret = f->ret;
+ n = f->n;
+ ret->min.x = f->r.min.x + n;
+ ret->min.y = f->r.min.y + n;
+ ret->max.x = f->r.max.x - n;
+ ret->max.y = f->r.max.y - n;
+}
+
+void
+Rect_dx(void *fp)
+{
+ F_Rect_dx *f;
+
+ f = fp;
+
+ *f->ret = f->r.max.x-f->r.min.x;
+}
+
+void
+Rect_dy(void *fp)
+{
+ F_Rect_dy *f;
+
+ f = fp;
+
+ *f->ret = f->r.max.y-f->r.min.y;
+}
+
+void
+Rect_size(void *fp)
+{
+ F_Rect_size *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->r.max.x-f->r.min.x;
+ ret->y = f->r.max.y-f->r.min.y;
+}
diff --git a/libinterp/heap.c b/libinterp/heap.c
new file mode 100644
index 00000000..5eff79a5
--- /dev/null
+++ b/libinterp/heap.c
@@ -0,0 +1,499 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "pool.h"
+#include "raise.h"
+
+void freearray(Heap*, int);
+void freelist(Heap*, int);
+void freemodlink(Heap*, int);
+void freechan(Heap*, int);
+Type Tarray = { 1, freearray, markarray, sizeof(Array) };
+Type Tstring = { 1, freestring, noptrs, sizeof(String) };
+Type Tlist = { 1, freelist, marklist, sizeof(List) };
+Type Tmodlink = { 1, freemodlink, markheap, -1, 1, 0, 0, { 0x80 } };
+Type Tchannel = { 1, freechan, markheap, sizeof(Channel), 1,0,0,{0x80} };
+Type Tptr = { 1, 0, markheap, sizeof(WORD*), 1, 0, 0, { 0x80 } };
+Type Tbyte = { 1, 0, 0, 1 };
+Type Tword = { 1, 0, 0, sizeof(WORD) };
+Type Tlong = { 1, 0, 0, sizeof(LONG) };
+Type Treal = { 1, 0, 0, sizeof(REAL) };
+
+extern Pool* heapmem;
+extern int mutator;
+
+void (*heapmonitor)(int, void*, ulong);
+
+#define BIT(bt, nb) (bt & (1<<nb))
+
+void
+freeptrs(void *v, Type *t)
+{
+ int c;
+ WORD **w, *x;
+ uchar *p, *ep;
+
+ if(t->np == 0)
+ return;
+
+ w = (WORD**)v;
+ p = t->map;
+ ep = p + t->np;
+ while(p < ep) {
+ c = *p;
+ if(c != 0) {
+ if(BIT(c, 0) && (x = w[7]) != H) destroy(x);
+ if(BIT(c, 1) && (x = w[6]) != H) destroy(x);
+ if(BIT(c, 2) && (x = w[5]) != H) destroy(x);
+ if(BIT(c, 3) && (x = w[4]) != H) destroy(x);
+ if(BIT(c, 4) && (x = w[3]) != H) destroy(x);
+ if(BIT(c, 5) && (x = w[2]) != H) destroy(x);
+ if(BIT(c, 6) && (x = w[1]) != H) destroy(x);
+ if(BIT(c, 7) && (x = w[0]) != H) destroy(x);
+ }
+ p++;
+ w += 8;
+ }
+}
+
+/*
+void
+nilptrs(void *v, Type *t)
+{
+ int c, i;
+ WORD **w;
+ uchar *p, *ep;
+
+ w = (WORD**)v;
+ p = t->map;
+ ep = p + t->np;
+ while(p < ep) {
+ c = *p;
+ for(i = 0; i < 8; i++){
+ if(BIT(c, 7)) *w = H;
+ c <<= 1;
+ w++;
+ }
+ p++;
+ }
+}
+*/
+
+void
+freechan(Heap *h, int swept)
+{
+ Channel *c;
+
+ USED(swept);
+ c = H2D(Channel*, h);
+ if(c->mover == movtmp)
+ freetype(c->mid.t);
+ killcomm(&c->send);
+ killcomm(&c->recv);
+ if (!swept && c->buf != H)
+ destroy(c->buf);
+}
+
+void
+freestring(Heap *h, int swept)
+{
+ String *s;
+
+ USED(swept);
+ s = H2D(String*, h);
+ if(s->tmp != nil)
+ free(s->tmp);
+}
+
+void
+freearray(Heap *h, int swept)
+{
+ int i;
+ Type *t;
+ uchar *v;
+ Array *a;
+
+ a = H2D(Array*, h);
+ t = a->t;
+
+ if(!swept) {
+ if(a->root != H)
+ destroy(a->root);
+ else
+ if(t->np != 0) {
+ v = a->data;
+ for(i = 0; i < a->len; i++) {
+ freeptrs(v, t);
+ v += t->size;
+ }
+ }
+ }
+ if(t->ref-- == 1) {
+ free(t->initialize);
+ free(t);
+ }
+}
+
+void
+freelist(Heap *h, int swept)
+{
+ Type *t;
+ List *l;
+ Heap *th;
+
+ l = H2D(List*, h);
+ t = l->t;
+
+ if(t != nil) {
+ if(!swept && t->np)
+ freeptrs(l->data, t);
+ t->ref--;
+ if(t->ref == 0) {
+ free(t->initialize);
+ free(t);
+ }
+ }
+ if(swept)
+ return;
+ l = l->tail;
+ while(l != (List*)H) {
+ t = l->t;
+ th = D2H((ulong)l);
+ if(th->ref-- != 1)
+ break;
+ th->t->ref--; /* should be &Tlist and ref shouldn't go to 0 here nor be 0 already */
+ if(t != nil) {
+ if (t->np)
+ freeptrs(l->data, t);
+ t->ref--;
+ if(t->ref == 0) {
+ free(t->initialize);
+ free(t);
+ }
+ }
+ l = l->tail;
+ if(heapmonitor != nil)
+ heapmonitor(1, th, 0);
+ poolfree(heapmem, th);
+ }
+}
+
+void
+freemodlink(Heap *h, int swept)
+{
+ Modlink *ml;
+
+ ml = H2D(Modlink*, h);
+ if(ml->m->rt == DYNMOD)
+ freedyndata(ml);
+ else if(!swept)
+ destroy(ml->MP);
+ unload(ml->m);
+}
+
+int
+heapref(void *v)
+{
+ return D2H(v)->ref;
+}
+
+void
+freeheap(Heap *h, int swept)
+{
+ Type *t;
+
+ if(swept)
+ return;
+
+ t = h->t;
+ if (t->np)
+ freeptrs(H2D(void*, h), t);
+}
+
+void
+destroy(void *v)
+{
+ Heap *h;
+ Type *t;
+
+ if(v == H)
+ return;
+
+ h = D2H(v);
+ { Bhdr *b; D2B(b, h); } /* consistency check */
+
+ if(--h->ref > 0 || gchalt > 64) /* Protect 'C' thread stack */
+ return;
+
+ if(heapmonitor != nil)
+ heapmonitor(1, h, 0);
+ t = h->t;
+ if(t != nil) {
+ gclock();
+ t->free(h, 0);
+ gcunlock();
+ freetype(t);
+ }
+ poolfree(heapmem, h);
+}
+
+void
+freetype(Type *t)
+{
+ if(t == nil || --t->ref > 0)
+ return;
+
+ free(t->initialize);
+ free(t);
+}
+
+void
+incmem(void *vw, Type *t)
+{
+ Heap *h;
+ uchar *p;
+ int i, c, m;
+ WORD **w, **q, *wp;
+
+ w = (WORD**)vw;
+ p = t->map;
+ for(i = 0; i < t->np; i++) {
+ c = *p++;
+ if(c != 0) {
+ q = w;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if((c & m) && (wp = *q) != H) {
+ h = D2H(wp);
+ h->ref++;
+ Setmark(h);
+ }
+ q++;
+ }
+ }
+ w += 8;
+ }
+}
+
+void
+scanptrs(void *vw, Type *t, void (*f)(void*))
+{
+ uchar *p;
+ int i, c, m;
+ WORD **w, **q, *wp;
+
+ w = (WORD**)vw;
+ p = t->map;
+ for(i = 0; i < t->np; i++) {
+ c = *p++;
+ if(c != 0) {
+ q = w;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if((c & m) && (wp = *q) != H)
+ f(D2H(wp));
+ q++;
+ }
+ }
+ w += 8;
+ }
+}
+
+void
+initmem(Type *t, void *vw)
+{
+ int c;
+ WORD **w;
+ uchar *p, *ep;
+
+ w = (WORD**)vw;
+ p = t->map;
+ ep = p + t->np;
+ while(p < ep) {
+ c = *p;
+ if(c != 0) {
+ if(BIT(c, 0)) w[7] = H;
+ if(BIT(c, 1)) w[6] = H;
+ if(BIT(c, 2)) w[5] = H;
+ if(BIT(c, 3)) w[4] = H;
+ if(BIT(c, 4)) w[3] = H;
+ if(BIT(c, 5)) w[2] = H;
+ if(BIT(c, 6)) w[1] = H;
+ if(BIT(c, 7)) w[0] = H;
+ }
+ p++;
+ w += 8;
+ }
+}
+
+Heap*
+nheap(int n)
+{
+ Heap *h;
+
+ h = poolalloc(heapmem, sizeof(Heap)+n);
+ if(h == nil)
+ error(exHeap);
+
+ h->t = nil;
+ h->ref = 1;
+ h->color = mutator;
+ if(heapmonitor != nil)
+ heapmonitor(0, h, n);
+
+ return h;
+}
+
+Heap*
+heapz(Type *t)
+{
+ Heap *h;
+
+ h = poolalloc(heapmem, sizeof(Heap)+t->size);
+ if(h == nil)
+ error(exHeap);
+
+ h->t = t;
+ t->ref++;
+ h->ref = 1;
+ h->color = mutator;
+ memset(H2D(void*, h), 0, t->size);
+ if(t->np)
+ initmem(t, H2D(void*, h));
+ if(heapmonitor != nil)
+ heapmonitor(0, h, t->size);
+ return h;
+}
+
+Heap*
+heap(Type *t)
+{
+ Heap *h;
+
+ h = poolalloc(heapmem, sizeof(Heap)+t->size);
+ if(h == nil)
+ error(exHeap);
+
+ h->t = t;
+ t->ref++;
+ h->ref = 1;
+ h->color = mutator;
+ if(t->np)
+ initmem(t, H2D(void*, h));
+ if(heapmonitor != nil)
+ heapmonitor(0, h, t->size);
+ return h;
+}
+
+Heap*
+heaparray(Type *t, int sz)
+{
+ Heap *h;
+ Array *a;
+
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ initarray(t, a);
+ return h;
+}
+
+int
+hmsize(void *v)
+{
+ return poolmsize(heapmem, v);
+}
+
+void
+initarray(Type *t, Array *a)
+{
+ int i;
+ uchar *p;
+
+ t->ref++;
+ if(t->np == 0)
+ return;
+
+ p = a->data;
+ for(i = 0; i < a->len; i++) {
+ initmem(t, p);
+ p += t->size;
+ }
+}
+
+void*
+arraycpy(Array *sa)
+{
+ int i;
+ Heap *dh;
+ Array *da;
+ uchar *elemp;
+ void **sp, **dp;
+
+ if(sa == H)
+ return H;
+
+ dh = nheap(sizeof(Array) + sa->t->size*sa->len);
+ dh->t = &Tarray;
+ Tarray.ref++;
+ da = H2D(Array*, dh);
+ da->t = sa->t;
+ da->t->ref++;
+ da->len = sa->len;
+ da->root = H;
+ da->data = (uchar*)da + sizeof(Array);
+ if(da->t == &Tarray) {
+ dp = (void**)da->data;
+ sp = (void**)sa->data;
+ /*
+ * Maximum depth of this recursion is set by DADEPTH
+ * in include/isa.h
+ */
+ for(i = 0; i < sa->len; i++)
+ dp[i] = arraycpy(sp[i]);
+ }
+ else {
+ memmove(da->data, sa->data, da->len*sa->t->size);
+ elemp = da->data;
+ for(i = 0; i < sa->len; i++) {
+ incmem(elemp, da->t);
+ elemp += da->t->size;
+ }
+ }
+ return da;
+}
+
+void
+newmp(void *dst, void *src, Type *t)
+{
+ Heap *h;
+ int c, i, m;
+ void **uld, *wp, **q;
+
+ memmove(dst, src, t->size);
+ uld = dst;
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ if(c != 0) {
+ m = 0x80;
+ q = uld;
+ while(m != 0) {
+ if((m & c) && (wp = *q) != H) {
+ h = D2H(wp);
+ if(h->t == &Tarray)
+ *q = arraycpy(wp);
+ else {
+ h->ref++;
+ Setmark(h);
+ }
+ }
+ m >>= 1;
+ q++;
+ }
+ }
+ uld += 8;
+ }
+}
diff --git a/libinterp/heapaudit.c b/libinterp/heapaudit.c
new file mode 100644
index 00000000..80fffa3e
--- /dev/null
+++ b/libinterp/heapaudit.c
@@ -0,0 +1,198 @@
+#include "lib9.h"
+#include "interp.h"
+#include "pool.h"
+
+
+typedef struct Audit Audit;
+struct Audit
+{
+ Type* t;
+ ulong n;
+ ulong size;
+ Audit* hash;
+};
+Audit* ahash[128];
+extern Pool* heapmem;
+extern void conslog(char*, ...);
+#define conslog print
+
+typedef struct Typed Typed;
+typedef struct Ptyped Ptyped;
+
+extern Type Trdchan;
+extern Type Twrchan;
+
+struct Typed
+{
+ char* name;
+ Type* ptr;
+} types[] =
+{
+ {"array", &Tarray},
+ {"byte", &Tbyte},
+ {"channel", &Tchannel},
+ {"list", &Tlist},
+ {"modlink", &Tmodlink},
+ {"ptr", &Tptr},
+ {"string", &Tstring},
+
+ {"rdchan", &Trdchan},
+ {"wrchan", &Twrchan},
+ {"unspec", nil},
+
+ 0
+};
+
+extern Type* TDisplay;
+extern Type* TFont;
+extern Type* TImage;
+extern Type* TScreen;
+extern Type* TFD;
+extern Type* TFileIO;
+extern Type* Tread;
+extern Type* Twrite;
+extern Type* fakeTkTop;
+
+extern Type* TSigAlg;
+extern Type* TCertificate;
+extern Type* TSK;
+extern Type* TPK;
+extern Type* TDigestState;
+extern Type* TAuthinfo;
+extern Type* TDESstate;
+extern Type* TIPint;
+
+struct Ptyped
+{
+ char* name;
+ Type** ptr;
+} ptypes[] =
+{
+ {"Display", &TDisplay},
+ {"Font", &TFont},
+ {"Image", &TImage},
+ {"Screen", &TScreen},
+
+ {"SigAlg", &TSigAlg},
+ {"Certificate", &TCertificate},
+ {"SK", &TSK},
+ {"PK", &TPK},
+ {"DigestState", &TDigestState},
+ {"Authinfo", &TAuthinfo},
+ {"DESstate", &TDESstate},
+ {"IPint", &TIPint},
+
+ {"FD", &TFD},
+ {"FileIO", &TFileIO},
+
+/* {"Fioread", &Tread}, */
+/* {"Fiowrite", &Twrite}, */
+
+ {"TkTop", &fakeTkTop},
+
+ 0
+};
+
+static Audit **
+auditentry(Type *t)
+{
+ Audit **h, *a;
+
+ for(h = &ahash[((ulong)t>>2)%nelem(ahash)]; (a = *h) != nil; h = &a->hash)
+ if(a->t == t)
+ break;
+ return h;
+}
+
+void
+heapaudit(void)
+{
+ Type *t;
+ Heap *h;
+ List *l;
+ Array *r;
+ Module *m;
+ int i, ntype, n;
+ Bhdr *b, *base, *limit;
+ Audit *a, **hash;
+
+ acquire();
+
+ b = poolchain(heapmem);
+ base = b;
+ limit = B2LIMIT(b);
+
+ while(b != nil) {
+ if(b->magic == MAGIC_A) {
+ h = B2D(b);
+ t = h->t;
+ n = 1;
+ if(t == &Tlist) {
+ l = H2D(List*, h);
+ t = l->t;
+ } else if(t == &Tarray) {
+ r = H2D(Array*, h);
+ t = r->t;
+ n = r->len;
+ }
+ hash = auditentry(t);
+ if((a = *hash) == nil){
+ a = malloc(sizeof(Audit));
+ if(a == nil)
+ continue;
+ a->n = 1;
+ a->t = t;
+ a->hash = *hash;
+ *hash = a;
+ }else
+ a->n++;
+ if(t != nil && t != &Tmodlink && t != &Tstring)
+ a->size += t->size*n;
+ else
+ a->size += b->size;
+ }
+ b = B2NB(b);
+ if(b >= limit) {
+ base = base->clink;
+ if(base == nil)
+ break;
+ b = base;
+ limit = B2LIMIT(base);
+ }
+ }
+
+ for(m = modules; m != nil; m = m->link) {
+ for(i = 0; i < m->ntype; i++)
+ if((a = *auditentry(m->type[i])) != nil) {
+ conslog("%8ld %8lud %3d %s\n", a->n, a->size, i, m->path);
+ a->size = 0;
+ break;
+ }
+ }
+
+ for(i = 0; (t = types[i].ptr) != nil; i++)
+ if((a = *auditentry(t)) != nil){
+ conslog("%8ld %8lud %s\n", a->n, a->size, types[i].name);
+ a->size = 0;
+ break;
+ }
+
+ for(i = 0; ptypes[i].name != nil; i++)
+ if((a = *auditentry(*ptypes[i].ptr)) != nil){
+ conslog("%8ld %8lud %s\n", a->n, a->size, ptypes[i].name);
+ a->size = 0;
+ break;
+ }
+
+ ntype = 0;
+ for(i = 0; i < nelem(ahash); i++)
+ while((a = ahash[i]) != nil){
+ ahash[i] = a->hash;
+ if(a->size != 0)
+ conslog("%8ld %8lud %p\n", a->n, a->size, a->t);
+ free(a);
+ ntype++;
+ }
+
+ release();
+}
diff --git a/libinterp/ipint.c b/libinterp/ipint.c
new file mode 100644
index 00000000..61c577fa
--- /dev/null
+++ b/libinterp/ipint.c
@@ -0,0 +1,547 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "../libkeyring/keys.h"
+#include "raise.h"
+
+enum {
+ PSEUDO=0,
+ REALLY,
+};
+
+void getRandBetween(BigInt p, BigInt q, BigInt result, int type);
+
+extern Type *TIPint;
+#define MP(x) (((IPint*)(x))->b)
+
+Keyring_IPint*
+newIPint(BigInt b)
+{
+ Heap *h;
+ IPint *ip;
+
+ if(b == nil)
+ error(exHeap);
+ h = heap(TIPint); /* TO DO: loss if heap fails */
+ ip = H2D(IPint*, h);
+ ip->b = b;
+ return (Keyring_IPint*)ip;
+}
+
+void
+freeIPint(Heap *h, int swept)
+{
+ IPint *ip;
+
+ USED(swept);
+ ip = H2D(IPint*, h);
+ if(ip->b)
+ mpfree(ip->b);
+ freeheap(h, 0);
+}
+
+void
+IPint_iptob64(void *fp)
+{
+ F_IPint_iptob64 *f;
+ char buf[MaxBigBytes];
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ mptoa(MP(f->i), 64, buf, sizeof(buf));
+ retstr(buf, f->ret);
+}
+
+void
+IPint_iptobytes(void *fp)
+{
+ F_IPint_iptobytes *f;
+ uchar buf[MaxBigBytes];
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ /* TO DO: two's complement or have ipmagtobe? */
+ *f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil)); /* for now we'll ignore sign */
+}
+
+void
+IPint_iptobebytes(void *fp)
+{
+ F_IPint_iptobebytes *f;
+ uchar buf[MaxBigBytes];
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ *f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil));
+}
+
+void
+IPint_iptostr(void *fp)
+{
+ F_IPint_iptostr *f;
+ char buf[MaxBigBytes];
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ mptoa(MP(f->i), f->base, buf, sizeof(buf));
+ retstr(buf, f->ret);
+}
+
+void
+IPint_b64toip(void *fp)
+{
+ F_IPint_b64toip *f;
+ BigInt b;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->str == H)
+ error(exNilref);
+
+ b = strtomp(string2c(f->str), nil, 64, nil);
+ *f->ret = newIPint(b);
+}
+
+void
+IPint_bytestoip(void *fp)
+{
+ F_IPint_bytestoip *f;
+ BigInt b;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->buf == H)
+ error(exNilref);
+
+ b = betomp(f->buf->data, f->buf->len, nil); /* for now we'll ignore sign */
+ *f->ret = newIPint(b);
+}
+
+void
+IPint_bebytestoip(void *fp)
+{
+ F_IPint_bebytestoip *f;
+ BigInt b;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mag == H)
+ error(exNilref);
+
+ b = betomp(f->mag->data, f->mag->len, nil);
+ *f->ret = newIPint(b);
+}
+
+void
+IPint_strtoip(void *fp)
+{
+ F_IPint_strtoip *f;
+ BigInt b;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->str == H)
+ return;
+
+ b = strtomp(string2c(f->str), nil, f->base, nil);
+ *f->ret = newIPint(b);
+}
+
+/* create a random integer */
+void
+IPint_random(void *fp)
+{
+ F_IPint_random *f;
+ BigInt b, min, max;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ b = itomp(1, nil);
+ min = mpnew(0);
+ max = mpnew(0);
+ mpleft(b, f->minbits, min);
+ mpleft(b, f->maxbits, max);
+
+ release();
+ getRandBetween(min, max, b, PSEUDO); /* TO DO */
+ acquire();
+
+ mpfree(min);
+ mpfree(max);
+ *f->ret = newIPint(b);
+}
+
+/* number of bits in number */
+void
+IPint_bits(void *fp)
+{
+ F_IPint_bits *f;
+ int n;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->i == H)
+ return;
+
+ n = mpsignif(MP(f->i));
+ if(n == 0)
+ n = 1; /* compatibility */
+ *f->ret = n;
+}
+
+/* create a new IP from an int */
+void
+IPint_inttoip(void *fp)
+{
+ F_IPint_inttoip *f;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ *f->ret = newIPint(itomp(f->i, nil));
+}
+
+void
+IPint_iptoint(void *fp)
+{
+ F_IPint_iptoint *f;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->i == H)
+ return;
+ *f->ret = mptoi(MP(f->i));
+}
+
+/* modular exponentiation */
+void
+IPint_expmod(void *fp)
+{
+ F_IPint_expmod *f;
+ BigInt ret, mod;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->base == H || f->exp == H)
+ error(exNilref);
+
+ mod = nil;
+ if(f->mod != H)
+ mod = MP(f->mod);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpexp(MP(f->base), MP(f->exp), mod, ret);
+ *f->ret = newIPint(ret);
+}
+
+/* multiplicative inverse */
+void
+IPint_invert(void *fp)
+{
+ F_IPint_invert *f;
+ BigInt ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ ret = mpnew(0);
+ if(ret != nil)
+ mpinvert(MP(f->base), MP(f->mod), ret);
+ *f->ret = newIPint(ret);
+}
+
+/* basic math */
+void
+IPint_add(void *fp)
+{
+ F_IPint_add *f;
+ BigInt i1, i2, ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i1 == H || f->i2 == H)
+ error(exNilref);
+
+ i1 = ((IPint*)f->i1)->b;
+ i2 = ((IPint*)f->i2)->b;
+ ret = mpnew(0);
+ if(ret != nil)
+ mpadd(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_sub(void *fp)
+{
+ F_IPint_sub *f;
+ BigInt i1, i2, ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i1 == H || f->i2 == H)
+ error(exNilref);
+
+ i1 = ((IPint*)f->i1)->b;
+ i2 = ((IPint*)f->i2)->b;
+ ret = mpnew(0);
+ if(ret != nil)
+ mpsub(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_mul(void *fp)
+{
+ F_IPint_mul *f;
+ BigInt i1, i2, ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i1 == H || f->i2 == H)
+ error(exNilref);
+
+ i1 = ((IPint*)f->i1)->b;
+ i2 = ((IPint*)f->i2)->b;
+ ret = mpnew(0);
+ if(ret != nil)
+ mpmul(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_div(void *fp)
+{
+ F_IPint_div *f;
+ BigInt i1, i2, quo, rem;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->i1 == H || f->i2 == H)
+ error(exNilref);
+
+ i1 = ((IPint*)f->i1)->b;
+ i2 = ((IPint*)f->i2)->b;
+ quo = mpnew(0);
+ if(quo == nil)
+ error(exHeap);
+ rem = mpnew(0);
+ if(rem == nil){
+ mpfree(quo);
+ error(exHeap);
+ }
+ mpdiv(i1, i2, quo, rem);
+
+ f->ret->t0 = newIPint(quo);
+ f->ret->t1 = newIPint(rem);
+}
+void
+IPint_neg(void *fp)
+{
+ F_IPint_neg *f;
+ BigInt i, ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ i = ((IPint*)f->i)->b;
+ ret = mpcopy(i);
+ if(ret == nil)
+ error(exHeap);
+ ret->sign = -ret->sign;
+
+ *f->ret = newIPint(ret);
+}
+
+/* copy */
+void
+IPint_copy(void *fp)
+{
+ F_IPint_copy *f;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ return;
+
+ *f->ret = newIPint(mpcopy(MP(f->i)));
+}
+
+
+/* equality */
+void
+IPint_eq(void *fp)
+{
+ F_IPint_eq *f;
+
+ f = fp;
+ *f->ret = 0;
+
+ if(f->i1 == H || f->i2 == H)
+ return;
+
+ *f->ret = mpcmp(MP(f->i1), MP(f->i2)) == 0;
+}
+
+/* compare */
+void
+IPint_cmp(void *fp)
+{
+ F_IPint_eq *f;
+
+ f = fp;
+ *f->ret = 0;
+
+ if(f->i1 == H || f->i2 == H)
+ error(exNilref);
+
+ *f->ret = mpcmp(MP(f->i1), MP(f->i2));
+}
+
+/* shifts */
+void
+IPint_shl(void *fp)
+{
+ F_IPint_shl *f;
+ BigInt ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ ret = mpnew(0);
+ if(ret != nil)
+ mpleft(MP(f->i), f->n, ret);
+ *f->ret = newIPint(ret);
+}
+void
+IPint_shr(void *fp)
+{
+ F_IPint_shr *f;
+ BigInt ret;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->i == H)
+ error(exNilref);
+
+ ret = mpnew(0);
+ if(ret != nil)
+ mpright(MP(f->i), f->n, ret);
+ *f->ret = newIPint(ret);
+}
+
+/*
+ * return a random number between a and b
+ */
+void
+getRandBetween(BigInt p, BigInt q, BigInt result, int type)
+{
+ BigInt T, slop, r, diff, one, two;
+ int length;
+
+if(0)print("1");
+ diff = mpnew(0);
+ one = itomp(1, nil);
+
+ /* smaller in p, larger in q */
+ if (mpcmp(p, q) > 0) {
+ T = p; p = q; q = T;
+ }
+
+ mpsub(q, p, diff);
+
+ two = itomp(2, nil);
+ if(mpcmp(diff, two) < 0){
+ mpfree(two);
+ itomp(0, result);
+ return;
+ }
+ mpfree(two);
+
+ /* generate a random number between 0 and diff */
+ T = mpnew(0);
+ slop = mpnew(0);
+ mpleft(one, mpsignif(diff), T);
+ length = mpsignif(T);
+
+ mpmod(T, diff, slop);
+ mpfree(T);
+
+ r = mpnew(0);
+ do {
+if(0)print("3");
+ mprand(length, type == PSEUDO? prng: genrandom, r);
+if(0)print("4");
+ } while (mpcmp(r, slop) < 0);
+ mpfree(slop);
+
+ mpmod(r, diff, result);
+ mpfree(r);
+ mpfree(diff);
+ mpfree(one);
+
+ /* add smaller number back in */
+ mpadd(result, p, result);
+
+if(0)print("2");
+}
diff --git a/libinterp/keyring.c b/libinterp/keyring.c
new file mode 100644
index 00000000..9182773a
--- /dev/null
+++ b/libinterp/keyring.c
@@ -0,0 +1,2511 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include "keyring.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+#include "../libkeyring/keys.h"
+
+
+enum {
+ PSEUDO=0,
+ REALLY,
+};
+void getRandBetween(BigInt p, BigInt q, BigInt result, int type);
+
+Type *TSigAlg;
+Type *TCertificate;
+Type *TSK;
+Type *TPK;
+Type *TDigestState;
+Type *TAuthinfo;
+Type *TAESstate;
+Type *TDESstate;
+Type *TIDEAstate;
+Type *TRC4state;
+Type *TIPint;
+
+enum {
+ Maxmsg= 4096
+};
+
+uchar IPintmap[] = Keyring_IPint_map;
+uchar SigAlgmap[] = Keyring_SigAlg_map;
+uchar SKmap[] = Keyring_SK_map;
+uchar PKmap[] = Keyring_PK_map;
+uchar Certificatemap[] = Keyring_Certificate_map;
+uchar DigestStatemap[] = Keyring_DigestState_map;
+uchar Authinfomap[] = Keyring_Authinfo_map;
+uchar AESstatemap[] = Keyring_AESstate_map;
+uchar DESstatemap[] = Keyring_DESstate_map;
+uchar IDEAstatemap[] = Keyring_IDEAstate_map;
+uchar RC4statemap[] = Keyring_RC4state_map;
+
+PK* checkPK(Keyring_PK *k);
+
+extern void setid(char*, int);
+extern vlong osusectime(void);
+extern Keyring_IPint* newIPint(BigInt);
+extern void freeIPint(Heap*, int);
+
+static char exBadSA[] = "bad signature algorithm";
+static char exBadSK[] = "bad secret key";
+static char exBadPK[] = "bad public key";
+static char exBadCert[] = "bad certificate";
+
+/*
+ * Infinite (actually kind of big) precision integers
+ */
+
+/* convert a Big to base64 ascii */
+int
+bigtobase64(BigInt b, char *buf, int len)
+{
+ uchar *p;
+ int n, rv, o;
+
+ n = (b->top+1)*Dbytes;
+ p = malloc(n+1);
+ if(p == nil)
+ goto Err;
+ n = mptobe(b, p+1, n, nil);
+ if(n < 0)
+ goto Err;
+ p[0] = 0;
+ if(n != 0 && (p[1]&0x80)){
+ /* force leading 0 byte for compatibility with older representation */
+ /* TO DO: if b->sign < 0, complement bits and add one */
+ o = 0;
+ n++;
+ }else
+ o = 1;
+ rv = enc64(buf, len, p+o, n);
+ free(p);
+ return rv;
+
+Err:
+ free(p);
+ if(len > 0){
+ *buf = '*';
+ return 1;
+ }
+ return 0;
+}
+
+/* convert a Big to base64 ascii for %U */
+int
+big64conv(Fmt *f)
+{
+ BigInt b;
+ char *buf;
+ int n;
+
+ b = va_arg(f->args, BigInt);
+ n = (b->top+1)*Dbytes + 1;
+ n = ((n+3)/3)*4 + 1;
+ buf = malloc(n);
+ bigtobase64(b, buf, n);
+ n = fmtstrcpy(f, buf);
+ free(buf);
+ return n;
+}
+
+/* convert a base64 string to a big */
+BigInt
+base64tobig(char *str, char **strp)
+{
+ int n;
+ char *p;
+ BigInt b;
+ uchar hex[(MaxBigBytes*6 + 7)/8];
+
+ for(p = str; *p && *p != '\n'; p++)
+ ;
+ n = dec64(hex, sizeof(hex), str, p - str);
+ b = betomp(hex, n, nil);
+ if(strp){
+ if(*p)
+ p++;
+ *strp = p;
+ }
+ return b;
+}
+
+/*
+ * signature algorithms
+ */
+enum
+{
+ Maxalg = 8
+};
+static SigAlgVec *algs[Maxalg];
+static int nalg;
+
+static SigAlg*
+newSigAlg(SigAlgVec *vec)
+{
+ Heap *h;
+ SigAlg *sa;
+
+ h = heap(TSigAlg);
+ sa = H2D(SigAlg*, h);
+ retstr(vec->name, &sa->x.name);
+ sa->vec = vec;
+ return sa;
+}
+
+static void
+freeSigAlg(Heap *h, int swept)
+{
+ if(!swept)
+ freeheap(h, 0);
+}
+
+SigAlgVec*
+findsigalg(char *name)
+{
+ SigAlgVec **sap;
+
+ for(sap = algs; sap < &algs[nalg]; sap++)
+ if(strcmp(name, (*sap)->name) == 0)
+ return *sap;
+ return nil;
+}
+
+SigAlg*
+strtoalg(char *str, char **strp)
+{
+ int n;
+ char *p, name[20];
+ SigAlgVec *sa;
+
+
+ p = strchr(str, '\n');
+ if(p == 0){
+ p = str + strlen(str);
+ if(strp)
+ *strp = p;
+ } else {
+ if(strp)
+ *strp = p+1;
+ }
+
+ n = p - str;
+ if(n < sizeof(name)){
+ strncpy(name, str, n);
+ name[n] = 0;
+ sa = findsigalg(name);
+ if(sa != nil)
+ return newSigAlg(sa);
+ }
+ return nil;
+}
+
+static SigAlg*
+checkSigAlg(Keyring_SigAlg *ksa)
+{
+ SigAlgVec **sap;
+ SigAlg *sa;
+
+ sa = (SigAlg*)ksa;
+
+ for(sap = algs; sap < &algs[Maxalg]; sap++)
+ if(sa->vec == *sap)
+ return sa;
+ errorf("%s: %s", exType, exBadSA);
+ return nil;
+}
+
+/*
+ * parse next new line terminated string into a String
+ */
+String*
+strtostring(char *str, char **strp)
+{
+ char *p;
+ String *s;
+
+ p = strchr(str, '\n');
+ if(p == 0)
+ p = str + strlen(str);
+ s = H;
+ retnstr(str, p - str, &s);
+
+ if(strp){
+ if(*p)
+ p++;
+ *strp = p;
+ }
+
+ return s;
+}
+
+/*
+ * private part of a key
+ */
+static SK*
+newSK(SigAlg *sa, String *owner, int increfsa)
+{
+ Heap *h;
+ SK *k;
+
+ h = heap(TSK);
+ k = H2D(SK*, h);
+ k->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ k->x.owner = owner;
+ k->key = 0;
+ return k;
+}
+
+static void
+freeSK(Heap *h, int swept)
+{
+ SK *k;
+ SigAlg *sa;
+
+ k = H2D(SK*, h);
+ sa = checkSigAlg(k->x.sa);
+ if(k->key)
+ (*sa->vec->skfree)(k->key);
+ freeheap(h, swept);
+}
+
+static SK*
+checkSK(Keyring_SK *k)
+{
+ SK *sk;
+
+ sk = (SK*)k;
+ if(sk == H || sk == nil || sk->key == 0 || D2H(sk)->t != TSK){
+ errorf("%s: %s", exType, exBadSK);
+ return nil;
+ }
+ return sk;
+}
+
+void
+Keyring_genSK(void *fp)
+{
+ F_Keyring_genSK *f;
+ SK *sk;
+ SigAlg *sa;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sa = strtoalg(string2c(f->algname), 0);
+ if(sa == nil)
+ return;
+
+ sk = newSK(sa, stringdup(f->owner), 0);
+ *f->ret = (Keyring_SK*)sk;
+ release();
+ sk->key = (*sa->vec->gensk)(f->length);
+ acquire();
+}
+
+void
+Keyring_genSKfromPK(void *fp)
+{
+ F_Keyring_genSKfromPK *f;
+ SigAlg *sa;
+ PK *pk;
+ SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ pk = checkPK(f->pk);
+ sa = checkSigAlg(pk->x.sa);
+ sk = newSK(sa, stringdup(f->owner), 1);
+ *f->ret = (Keyring_SK*)sk;
+ release();
+ sk->key = (*sa->vec->genskfrompk)(pk->key);
+ acquire();
+}
+
+/* converts a sequence of newline-separated base64-encoded BigInts to attr=hexval ... in f */
+static char*
+bigs2attr(Fmt *f, char *bigs, char **names)
+{
+ int i, n, nd;
+ char *b16, *vals[20];
+ uchar data[(MaxBigBytes*6 + 7)/8];
+
+ b16 = malloc(2*MaxBigBytes+1);
+ if(b16 == nil)
+ return nil;
+ n = getfields(bigs, vals, nelem(vals), 0, "\n");
+ for(i = 0; i < n-1; i++){
+ if(names == nil || names[i] == nil)
+ break; /* shouldn't happen */
+ nd = dec64(data, sizeof(data), vals[i], strlen(vals[i]));
+ if(nd < 0)
+ break;
+ enc16(b16, 2*MaxBigBytes+1, data, nd);
+ fmtprint(f, " %s=%s", names[i], b16);
+ }
+ free(b16);
+ return fmtstrflush(f);
+}
+
+void
+Keyring_sktoattr(void *fp)
+{
+ F_Keyring_sktoattr *f;
+ char *val, *buf;
+ SigAlg *sa;
+ Fmt o;
+ SK *sk;
+
+ f = fp;
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->sk2str)(sk->key, buf, Maxbuf);
+ fmtstrinit(&o);
+ fmtprint(&o, "alg=%q owner=%q", string2c(sa->x.name), string2c(sk->x.owner));
+ val = bigs2attr(&o, buf, sa->vec->skattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static int
+sktostr(SK *sk, char *buf, int len)
+{
+ int n;
+ SigAlg *sa;
+
+ sa = checkSigAlg(sk->x.sa);
+ n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name),
+ string2c(sk->x.owner));
+ return n + (*sa->vec->sk2str)(sk->key, buf+n, len - n);
+}
+
+void
+Keyring_sktostr(void *fp)
+{
+ F_Keyring_sktostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ sktostr(checkSK(f->sk), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+static SK*
+strtosk(char *buf)
+{
+ SK *sk;
+ char *p;
+ SigAlg *sa;
+ String *owner;
+ void *key;
+
+ sa = strtoalg(buf, &p);
+ if(sa == nil)
+ return H;
+ owner = strtostring(p, &p);
+ if(owner == H){
+ destroy(sa);
+ return H;
+ }
+
+ key = (*sa->vec->str2sk)(p, &p);
+ if(key == nil){
+ destroy(sa);
+ destroy(owner);
+ return H;
+ }
+ sk = newSK(sa, owner, 0);
+ sk->key = key;
+
+ return sk;
+}
+
+void
+Keyring_strtosk(void *fp)
+{
+ F_Keyring_strtosk *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ *f->ret = (Keyring_SK*)strtosk(string2c(f->s));
+}
+
+/*
+ * public part of a key
+ */
+PK*
+newPK(SigAlg *sa, String *owner, int increfsa)
+{
+ Heap *h;
+ PK *k;
+
+ h = heap(TPK);
+ k = H2D(PK*, h);
+ k->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ k->x.owner = owner;
+ k->key = 0;
+ return k;
+}
+
+void
+pkimmutable(PK *k)
+{
+ poolimmutable(D2H(k));
+ poolimmutable(D2H(k->x.sa));
+ poolimmutable(D2H(k->x.sa->name));
+ poolimmutable(D2H(k->x.owner));
+}
+
+void
+pkmutable(PK *k)
+{
+ poolmutable(D2H(k));
+ poolmutable(D2H(k->x.sa));
+ poolmutable(D2H(k->x.sa->name));
+ poolmutable(D2H(k->x.owner));
+}
+
+void
+freePK(Heap *h, int swept)
+{
+ PK *k;
+ SigAlg *sa;
+
+ k = H2D(PK*, h);
+ sa = checkSigAlg(k->x.sa);
+ if(k->key)
+ (*sa->vec->pkfree)(k->key);
+ freeheap(h, swept);
+}
+
+PK*
+checkPK(Keyring_PK *k)
+{
+ PK *pk;
+
+ pk = (PK*)k;
+ if(pk == H || pk == nil || pk->key == 0 || D2H(pk)->t != TPK){
+ errorf("%s: %s", exType, exBadPK);
+ return nil;
+ }
+ return pk;
+}
+
+void
+Keyring_sktopk(void *fp)
+{
+ F_Keyring_sktopk *f;
+ PK *pk;
+ SigAlg *sa;
+ SK *sk;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+ pk = newPK(sa, stringdup(sk->x.owner), 1);
+ pk->key = (*sa->vec->sk2pk)(sk->key);
+ *f->ret = (Keyring_PK*)pk;
+}
+
+static int
+pktostr(PK *pk, char *buf, int len)
+{
+ int n;
+ SigAlg *sa;
+
+ sa = checkSigAlg(pk->x.sa);
+ n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name), string2c(pk->x.owner));
+ return n + (*sa->vec->pk2str)(pk->key, buf+n, len - n);
+}
+
+void
+Keyring_pktostr(void *fp)
+{
+ F_Keyring_pktostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ pktostr(checkPK(f->pk), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+void
+Keyring_pktoattr(void *fp)
+{
+ F_Keyring_pktoattr *f;
+ char *val, *buf;
+ SigAlg *sa;
+ Fmt o;
+ PK *pk;
+
+ f = fp;
+ pk = checkPK(f->pk);
+ sa = checkSigAlg(pk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->pk2str)(pk->key, buf, Maxbuf);
+ fmtstrinit(&o);
+ fmtprint(&o, "alg=%q owner=%q", string2c(sa->x.name), string2c(pk->x.owner));
+ val = bigs2attr(&o, buf, sa->vec->pkattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static PK*
+strtopk(char *buf)
+{
+ PK *pk;
+ char *p;
+ SigAlg *sa;
+ String *owner;
+ void *key;
+
+ sa = strtoalg(buf, &p);
+ if(sa == nil)
+ return H;
+ owner = strtostring(p, &p);
+ if(owner == H){
+ destroy(sa);
+ return H;
+ }
+
+ key = (*sa->vec->str2pk)(p, &p);
+ if(key == nil){
+ destroy(sa);
+ destroy(owner);
+ return H;
+ }
+ pk = newPK(sa, owner, 0);
+ pk->key = key;
+
+ return pk;
+}
+
+void
+Keyring_strtopk(void *fp)
+{
+ F_Keyring_strtopk *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ *f->ret = (Keyring_PK*)strtopk(string2c(f->s));
+}
+
+/*
+ * Certificates/signatures
+ */
+
+void
+certimmutable(Certificate *c)
+{
+ poolimmutable(D2H(c));
+ poolimmutable(D2H(c->x.signer));
+ poolimmutable(D2H(c->x.ha));
+ poolimmutable(D2H(c->x.sa));
+ poolimmutable(D2H(c->x.sa->name));
+}
+
+void
+certmutable(Certificate *c)
+{
+ poolmutable(D2H(c));
+ poolmutable(D2H(c->x.signer));
+ poolmutable(D2H(c->x.ha));
+ Setmark(D2H(c->x.sa));
+ poolmutable(D2H(c->x.sa));
+ Setmark(D2H(c->x.sa->name));
+ poolmutable(D2H(c->x.sa->name));
+}
+
+Certificate*
+newCertificate(SigAlg *sa, String *ha, String *signer, long exp, int increfsa)
+{
+ Heap *h;
+ Certificate *c;
+
+ h = heap(TCertificate);
+ c = H2D(Certificate*, h);
+ c->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ c->x.signer = signer;
+ c->x.ha = ha;
+ c->x.exp = exp;
+ c->signa = 0;
+
+ return c;
+}
+
+void
+freeCertificate(Heap *h, int swept)
+{
+ Certificate *c;
+ SigAlg *sa;
+
+ c = H2D(Certificate*, h);
+ sa = checkSigAlg(c->x.sa);
+ if(c->signa)
+ (*sa->vec->sigfree)(c->signa);
+ freeheap(h, swept);
+}
+
+Certificate*
+checkCertificate(Keyring_Certificate *c)
+{
+ Certificate *cert;
+
+ cert = (Certificate*)c;
+ if(cert == H || cert == nil || cert->signa == 0 || D2H(cert)->t != TCertificate){
+ errorf("%s: %s", exType, exBadCert);
+ return nil;
+ }
+ return cert;
+}
+
+static int
+certtostr(Certificate *c, char *buf, int len)
+{
+ SigAlg *sa;
+ int n;
+
+ sa = checkSigAlg(c->x.sa);
+ n = snprint(buf, len, "%s\n%s\n%s\n%d\n", string2c(sa->x.name),
+ string2c(c->x.ha), string2c(c->x.signer), c->x.exp);
+ return n + (*sa->vec->sig2str)(c->signa, buf+n, len - n);
+}
+
+void
+Keyring_certtostr(void *fp)
+{
+ F_Keyring_certtostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ certtostr(checkCertificate(f->c), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+void
+Keyring_certtoattr(void *fp)
+{
+ F_Keyring_certtoattr *f;
+ char *val, *buf, *ha;
+ SigAlg *sa;
+ Fmt o;
+ Certificate *c;
+
+ f = fp;
+ c = checkCertificate(f->c);
+ sa = checkSigAlg(c->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->sig2str)(c->signa, buf, Maxbuf);
+ ha = string2c(c->x.ha);
+ if(strcmp(ha, "sha") == 0)
+ ha = "sha1"; /* normalise */
+ fmtstrinit(&o);
+ fmtprint(&o, "sigalg=%q-%q signer=%q expires=%ud", string2c(sa->x.name), ha,
+ string2c(c->x.signer), c->x.exp);
+ val = bigs2attr(&o, buf, sa->vec->sigattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static Certificate*
+strtocert(char *buf)
+{
+ Certificate *c;
+ char *p;
+ SigAlg *sa;
+ String *signer, *ha;
+ long exp;
+ void *signa;
+
+ sa = strtoalg(buf, &p);
+ if(sa == 0)
+ return H;
+
+ ha = strtostring(p, &p);
+ if(ha == H){
+ destroy(sa);
+ return H;
+ }
+
+ signer = strtostring(p, &p);
+ if(signer == H){
+ destroy(sa);
+ destroy(ha);
+ return H;
+ }
+
+ exp = strtoul(p, &p, 10);
+ if(*p)
+ p++;
+ signa = (*sa->vec->str2sig)(p, &p);
+ if(signa == nil){
+ destroy(sa);
+ destroy(ha);
+ destroy(signer);
+ return H;
+ }
+
+ c = newCertificate(sa, ha, signer, exp, 0);
+ c->signa = signa;
+
+ return c;
+}
+
+void
+Keyring_strtocert(void *fp)
+{
+ F_Keyring_strtocert *f;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ *f->ret = (Keyring_Certificate*)strtocert(string2c(f->s));
+}
+
+static Certificate*
+sign(SK *sk, char *ha, ulong exp, uchar *a, int len)
+{
+ Certificate *c;
+ BigInt b;
+ int n;
+ SigAlg *sa;
+ DigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+ String *hastr;
+
+ hastr = H;
+ sa = checkSigAlg(sk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return nil;
+
+ /* add signer name and expiration time to hash */
+ n = snprint(buf, Maxbuf, "%s %lud", string2c(sk->x.owner), exp);
+ if(strcmp(ha, "sha") == 0 || strcmp(ha, "sha1") == 0){
+ ds = sha1(a, len, 0, 0);
+ sha1((uchar*)buf, n, digest, ds);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(ha, "md5") == 0){
+ ds = md5(a, len, 0, 0);
+ md5((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(ha, "md4") == 0){
+ ds = md4(a, len, 0, 0);
+ md4((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return nil;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return nil;
+
+ /* sign */
+ retstr(ha, &hastr);
+ c = newCertificate(sa, hastr, stringdup(sk->x.owner), exp, 1);
+ certimmutable(c); /* hide from the garbage collector */
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+ mpfree(b);
+
+ return c;
+}
+
+void
+Keyring_sign(void *fp)
+{
+ F_Keyring_sign *f;
+ Certificate *c;
+ BigInt b;
+ int n;
+ SigAlg *sa;
+ SK *sk;
+ XDigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+
+ /* add signer name and expiration time to hash */
+ if(f->state == H)
+ return;
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+ ds = (XDigestState*)f->state;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(sk->x.owner), f->exp);
+ if(strcmp(string2c(f->ha), "sha") == 0 || strcmp(string2c(f->ha), "sha1") == 0){
+ sha1((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(f->ha), "md5") == 0){
+ md5((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(f->ha), "md4") == 0){
+ md4((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return;
+
+ /* sign */
+ c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), f->exp, 1);
+ *f->ret = (Keyring_Certificate*)c;
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+ mpfree(b);
+}
+
+static BigInt
+checkIPint(Keyring_IPint *v)
+{
+ IPint *ip;
+
+ ip = (IPint*)v;
+ if(ip == H || ip == nil || D2H(ip)->t != TIPint)
+ error(exType);
+ return ip->b;
+}
+
+void
+Keyring_signm(void *fp)
+{
+ F_Keyring_signm *f;
+ Certificate *c;
+ BigInt b;
+ SigAlg *sa;
+ SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+
+ if(f->m == H)
+ return;
+ b = checkIPint(f->m);
+
+ /* sign */
+ c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), 0, 1);
+ *f->ret = (Keyring_Certificate*)c;
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+}
+
+static int
+verify(PK *pk, Certificate *c, char *a, int len)
+{
+ BigInt b;
+ int n;
+ SigAlg *sa, *pksa;
+ DigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+
+ sa = checkSigAlg(c->x.sa);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return 0;
+
+ /* add signer name and expiration time to hash */
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return 0;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+ if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+ ds = sha1((uchar*)a, len, 0, 0);
+ sha1((uchar*)buf, n, digest, ds);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(c->x.ha), "md5") == 0){
+ ds = md5((uchar*)a, len, 0, 0);
+ md5((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(c->x.ha), "md4") == 0){
+ ds = md4((uchar*)a, len, 0, 0);
+ md4((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return 0;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return 0;
+ /* verify */
+ release();
+ n = (*sa->vec->verify)(b, c->signa, pk->key);
+ acquire();
+
+ mpfree(b);
+ return n;
+}
+
+void
+Keyring_verify(void *fp)
+{
+ F_Keyring_verify *f;
+ Certificate *c;
+ BigInt b;
+ int n;
+ SigAlg *sa, *pksa;
+ PK *pk;
+ XDigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+
+ f = fp;
+ *f->ret = 0;
+
+ c = checkCertificate(f->cert);
+ sa = checkSigAlg(c->x.sa);
+ pk = checkPK(f->pk);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return;
+
+ /* add signer name and expiration time to hash */
+ if(f->state == H)
+ return;
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+ ds = (XDigestState*)f->state;
+
+ if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+ sha1((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(c->x.ha), "md5") == 0){
+ md5((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(c->x.ha), "md4") == 0){
+ md4((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return;
+
+ /* verify */
+ release();
+ *f->ret = (*sa->vec->verify)(b, c->signa, pk->key);
+ acquire();
+
+ mpfree(b);
+}
+
+void
+Keyring_verifym(void *fp)
+{
+ F_Keyring_verifym *f;
+ Certificate *c;
+ SigAlg *sa, *pksa;
+ PK *pk;
+
+ f = fp;
+ *f->ret = 0;
+
+ c = checkCertificate(f->cert);
+ sa = checkSigAlg(c->x.sa);
+ pk = checkPK(f->pk);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return;
+
+ if(f->m == H)
+ return;
+
+ release();
+ *f->ret = (*sa->vec->verify)(checkIPint(f->m), c->signa, pk->key);
+ acquire();
+}
+
+/*
+ * digests
+ */
+void
+DigestState_copy(void *fp)
+{
+ F_DigestState_copy *f;
+ Heap *h;
+ XDigestState *ds;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->d != H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memmove(&ds->state, &((XDigestState*)f->d)->state, sizeof(ds->state));
+ *f->ret = (Keyring_DigestState*)ds;
+ }
+}
+
+static Keyring_DigestState*
+keyring_digest_x(Array *buf, int n, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cbuf, *cdigest;
+
+ if(buf != H){
+ if(n > buf->len)
+ n = buf->len;
+ cbuf = buf->data;
+ }else{
+ if(n != 0)
+ return H;
+ cbuf = nil;
+ }
+
+ if(digest != H){
+ if(digest->len < dlen)
+ return H;
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else {
+ D2H(state)->ref++;
+ ds = (XDigestState*)state;
+ }
+
+ (*fn)(cbuf, n, cdigest, &ds->state);
+
+ return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_sha1(void *fp)
+{
+ F_Keyring_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Keyring_md5(void *fp)
+{
+ F_Keyring_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Keyring_md4(void *fp)
+{
+ F_Keyring_md4 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Keyring_DigestState*
+keyring_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cdata, *cdigest;
+
+ if(data != H){
+ if(n > data->len)
+ n = data->len;
+ cdata = data->data;
+ }else{
+ if(n != 0)
+ return H;
+ cdata = nil;
+ }
+
+ if(key == H || key->len > 64)
+ return H;
+
+ if(digest != H){
+ if(digest->len < dlen)
+ return H;
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else {
+ D2H(state)->ref++;
+ ds = (XDigestState*)state;
+ }
+
+ (*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+ return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_hmac_sha1(void *fp)
+{
+ F_Keyring_hmac_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Keyring_hmac_md5(void *fp)
+{
+ F_Keyring_hmac_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Keyring_dhparams(void *fp)
+{
+ F_Keyring_dhparams *f;
+ EGpriv *egp;
+ BigInt p, alpha;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ release();
+ egp = eggen(f->nbits, 0);
+ acquire();
+ p = mpcopy(egp->pub.p);
+ alpha = mpcopy(egp->pub.alpha);
+ egprivfree(egp);
+ f->ret->t0 = newIPint(alpha);
+ f->ret->t1 = newIPint(p);
+}
+
+static int
+sendmsg(int fd, void *buf, int n)
+{
+ char num[10];
+
+ release();
+ snprint(num, sizeof(num), "%4.4d\n", n);
+ if(kwrite(fd, num, 5) != 5){
+ acquire();
+ return -1;
+ }
+ n = kwrite(fd, buf, n);
+ acquire();
+ return n;
+}
+
+void
+Keyring_sendmsg(void *fp)
+{
+ F_Keyring_sendmsg *f;
+ int n;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->buf == H || f->n < 0)
+ return;
+ n = f->buf->len;
+ if(n > f->n)
+ n = f->n;
+ *f->ret = sendmsg(f->fd->fd, f->buf->data, n);
+}
+
+static int
+senderr(int fd, char *err, int addrmt)
+{
+ char num[10];
+ int n, m;
+
+ release();
+ n = strlen(err);
+ m = 0;
+ if(addrmt)
+ m = strlen("remote: ");
+ snprint(num, sizeof(num), "!%3.3d\n", n+m);
+ if(kwrite(fd, num, 5) != 5){
+ acquire();
+ return -1;
+ }
+ if(addrmt)
+ kwrite(fd, "remote: ", m);
+ n = kwrite(fd, err, n);
+ acquire();
+ return n;
+}
+
+void
+Keyring_senderrmsg(void *fp)
+{
+ F_Keyring_senderrmsg *f;
+ char *s;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H)
+ return;
+ s = string2c(f->s);
+ if(senderr(f->fd->fd, s, 0) > 0)
+ *f->ret = 0;
+}
+
+static int
+nreadn(int fd, void *av, int n)
+{
+
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = kread(fd, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
+
+#define MSG "input or format error"
+
+static void
+getmsgerr(char *buf, int n, int r)
+{
+ char *e;
+ int l;
+
+ e = r>0? MSG: "hungup";
+ l = strlen(e)+1;
+ if(n > l)
+ n = l;
+ memmove(buf, e, n-1);
+ buf[n-1] = 0;
+}
+
+static int
+getmsg(int fd, char *buf, int n)
+{
+ char num[6];
+ int len, r;
+
+ release();
+ if((r = nreadn(fd, num, 5)) != 5){
+ getmsgerr(buf, n, r);
+ acquire();
+ return -1;
+ }
+ num[5] = 0;
+
+ if(num[0] == '!')
+ len = strtoul(num+1, 0, 10);
+ else
+ len = strtoul(num, 0, 10);
+
+ r = -1;
+ if(len < 0 || len >= n || (r = nreadn(fd, buf, len)) != len){
+ getmsgerr(buf, n, r);
+ acquire();
+ return -1;
+ }
+
+ buf[len] = 0;
+ acquire();
+ if(num[0] == '!')
+ return -len;
+
+ return len;
+}
+
+void
+Keyring_getmsg(void *fp)
+{
+ F_Keyring_getmsg *f;
+ char *buf;
+ int n;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ if(f->fd == H){
+ kwerrstr("nil fd");
+ return;
+ }
+
+ buf = malloc(Maxmsg);
+ if(buf == nil){
+ kwerrstr(exNomem);
+ return;
+ }
+
+ n = getmsg(f->fd->fd, buf, Maxmsg);
+ if(n < 0){
+ kwerrstr("%s", buf);
+ free(buf);
+ return;
+ }
+
+ *f->ret = mem2array(buf, n);
+ free(buf);
+}
+
+void
+Keyring_auth(void *fp)
+{
+ F_Keyring_auth *f;
+ BigInt r0, r1, p, alpha, alphar0, alphar1, alphar0r1, low;
+ SK *mysk;
+ PK *mypk, *spk, *hispk;
+ Certificate *cert, *hiscert, *alphacert;
+ char *buf, *err;
+ uchar *cvb;
+ int n, fd, version;
+ long now;
+
+ hispk = H;
+ hiscert = H;
+ alphacert = H;
+ err = nil;
+
+ /* null out the return values */
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ low = r0 = r1 = alphar0 = alphar1 = alphar0r1 = nil;
+
+ /* check args */
+ if(f->fd == H || f->fd->fd < 0){
+ retstr("bad fd", &f->ret->t0);
+ return;
+ }
+ fd = f->fd->fd;
+
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(exNomem, &f->ret->t0);
+ return;
+ }
+
+ /* send auth protocol version number */
+ if(sendmsg(fd, "1", 1) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ /* get auth protocol version number */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ version = atoi(buf);
+ if(version != 1 || n > 4){
+ err = "incompatible authentication protocol";
+ goto out;
+ }
+
+ if(f->info == H){
+ err = "no authentication information";
+ goto out;
+ }
+ if(f->info->p == H){
+ err = "missing diffie hellman mod";
+ goto out;
+ }
+ if(f->info->alpha == H){
+ err = "missing diffie hellman base";
+ goto out;
+ }
+ mysk = checkSK(f->info->mysk);
+ if(mysk == H){
+ err = "bad sk arg";
+ goto out;
+ }
+ mypk = checkPK(f->info->mypk);
+ if(mypk == H){
+ err = "bad pk arg";
+ goto out;
+ }
+ cert = checkCertificate(f->info->cert);
+ if(cert == H){
+ err = "bad certificate arg";
+ goto out;
+ }
+ spk = checkPK(f->info->spk);
+ if(spk == H){
+ err = "bad signer key arg";
+ goto out;
+ }
+
+ /* get alpha and p */
+ p = ((IPint*)f->info->p)->b;
+ alpha = ((IPint*)f->info->alpha)->b;
+
+ if(p->sign == -1) {
+ err = "-ve modulus";
+ goto out;
+ }
+
+ low = mpnew(0);
+ r0 = mpnew(0);
+ r1 = mpnew(0);
+ alphar0 = mpnew(0);
+ alphar0r1 = mpnew(0);
+
+ /* generate alpha**r0 */
+if(0)print("X");
+ release();
+ mpright(p, mpsignif(p)/4, low);
+ getRandBetween(low, p, r0, PSEUDO);
+ mpexp(alpha, r0, p, alphar0);
+ acquire();
+if(0)print("Y");
+
+ /* send alpha**r0 mod p, mycert, and mypk */
+ n = bigtobase64(alphar0, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ n = certtostr(cert, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ n = pktostr(mypk, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ /* get alpha**r1 mod p, hiscert, hispk */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ alphar1 = strtomp(buf, nil, 64, nil);
+
+ /* trying a fast one */
+ if(mpcmp(p, alphar1) <= 0){
+ err = "implausible parameter value";
+ goto out;
+ }
+
+ /* if alpha**r1 == alpha**r0, someone may be trying a replay */
+ if(mpcmp(alphar0, alphar1) == 0){
+ err = "possible replay attack";
+ goto out;
+ }
+
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ hiscert = strtocert(buf);
+ if(hiscert == H){
+ err = "bad certificate";
+ goto out;
+ }
+ certimmutable(hiscert); /* hide from the garbage collector */
+
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ hispk = strtopk(buf);
+ if(hispk == H){
+ err = "bad public key";
+ goto out;
+ }
+ pkimmutable(hispk); /* hide from the garbage collector */
+
+ /* verify his public key */
+ if(verify(spk, hiscert, buf, n) == 0){
+ err = "pk doesn't match certificate";
+ goto out;
+ }
+
+ /* check expiration date - in seconds of epoch */
+
+ now = osusectime()/1000000;
+ if(hiscert->x.exp != 0 && hiscert->x.exp <= now){
+ err = "certificate expired";
+ goto out;
+ }
+
+ /* sign alpha**r0 and alpha**r1 and send */
+ n = bigtobase64(alphar0, buf, Maxbuf);
+ n += bigtobase64(alphar1, buf+n, Maxbuf-n);
+ alphacert = sign(mysk, "sha1", 0, (uchar*)buf, n);
+ n = certtostr(alphacert, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+ certmutable(alphacert);
+ destroy(alphacert);
+ alphacert = H;
+
+ /* get signature of alpha**r1 and alpha**r0 and verify */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ alphacert = strtocert(buf);
+ if(alphacert == H){
+ err = "alpha**r1 doesn't match certificate";
+ goto out;
+ }
+ certimmutable(alphacert); /* hide from the garbage collector */
+ n = bigtobase64(alphar1, buf, Maxbuf);
+ n += bigtobase64(alphar0, buf+n, Maxbuf-n);
+ if(verify(hispk, alphacert, buf, n) == 0){
+ err = "bad certificate";
+ goto out;
+ }
+
+ /* we are now authenticated and have a common secret, alpha**(r0*r1) */
+ f->ret->t0 = stringdup(hispk->x.owner);
+ mpexp(alphar1, r0, p, alphar0r1);
+ n = mptobe(alphar0r1, nil, Maxbuf, &cvb);
+ if(n < 0){
+ err = "bad conversion";
+ goto out;
+ }
+ f->ret->t1 = mem2array(cvb, n);
+ free(cvb);
+
+out:
+ /* return status */
+ if(f->ret->t0 == H){
+ if(err == buf)
+ senderr(fd, "missing your authentication data", 1);
+ else
+ senderr(fd, err, 1);
+ }else
+ sendmsg(fd, "OK", 2);
+
+ /* read responses */
+ if(err != buf){
+ for(;;){
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ if(err == nil){
+ if(n < -1)
+ err = buf;
+ else
+ err = MSG;
+ }
+ break;
+ }
+ if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
+ break;
+ }
+ }
+
+ /* set error and id to nobody */
+ if(f->ret->t0 == H){
+ if(err == nil)
+ err = MSG;
+ retstr(err, &f->ret->t0);
+ if(f->setid)
+ setid("nobody", 1);
+ } else {
+ /* change user id */
+ if(f->setid)
+ setid(string2c(f->ret->t0), 1);
+ }
+
+ /* free resources */
+ if(hispk != H){
+ pkmutable(hispk);
+ destroy(hispk);
+ }
+ if(hiscert != H){
+ certmutable(hiscert);
+ destroy(hiscert);
+ }
+ if(alphacert != H){
+ certmutable(alphacert);
+ destroy(alphacert);
+ }
+ free(buf);
+ if(low != nil){
+ mpfree(low);
+ mpfree(r0);
+ mpfree(r1);
+ mpfree(alphar0);
+ mpfree(alphar1);
+ mpfree(alphar0r1);
+ }
+}
+
+static Keyring_Authinfo*
+newAuthinfo(void)
+{
+ return H2D(Keyring_Authinfo*, heap(TAuthinfo));
+}
+
+void
+Keyring_writeauthinfo(void *fp)
+{
+ F_Keyring_writeauthinfo *f;
+ int n, fd;
+ char *buf;
+ PK *spk;
+ SK *mysk;
+ Certificate *c;
+
+ f = fp;
+ *f->ret = -1;
+
+ if(f->filename == H)
+ return;
+ if(f->info == H)
+ return;
+ if(f->info->alpha == H || f->info->p == H)
+ return;
+ if(((IPint*)f->info->alpha)->b == 0 || ((IPint*)f->info->p)->b == H)
+ return;
+ spk = checkPK(f->info->spk);
+ mysk = checkSK(f->info->mysk);
+ c = checkCertificate(f->info->cert);
+
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+
+ /*
+ * The file may already exist or be a file2chan file so first
+ * try opening with truncation since create will change the
+ * permissions of the file and create doesn't work with a
+ * file2chan.
+ */
+ release();
+ fd = kopen(string2c(f->filename), OTRUNC|OWRITE);
+ if(fd < 0)
+ fd = kcreate(string2c(f->filename), OWRITE, 0600);
+ if(fd < 0)
+ fd = kopen(string2c(f->filename), OWRITE);
+ acquire();
+ if(fd < 0)
+ goto out;
+
+ /* signer's public key */
+ n = pktostr(spk, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* certificate for my public key */
+ n = certtostr(c, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* my secret/public key */
+ n = sktostr(mysk, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* diffie hellman base */
+ n = bigtobase64(((IPint*)f->info->alpha)->b, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* diffie hellman modulus */
+ n = bigtobase64(((IPint*)f->info->p)->b, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ *f->ret = 0;
+out:
+ free(buf);
+ if(fd >= 0){
+ release();
+ kclose(fd);
+ acquire();
+ }
+}
+
+void
+Keyring_readauthinfo(void *fp)
+{
+ F_Keyring_readauthinfo *f;
+ int fd;
+ char *buf;
+ int n, ok;
+ PK *mypk;
+ SK *mysk;
+ SigAlg *sa;
+ Keyring_Authinfo *ai;
+ BigInt b;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ ok = 0;
+
+ if(f->filename == H)
+ return;
+
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+
+ ai = newAuthinfo();
+ *f->ret = ai;
+
+ release();
+ fd = kopen(string2c(f->filename), OREAD);
+ acquire();
+ if(fd < 0)
+ goto out;
+
+ /* signer's public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+
+ ai->spk = (Keyring_PK*)strtopk(buf);
+ if(ai->spk == H)
+ goto out;
+
+ /* certificate for my public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ ai->cert = (Keyring_Certificate*)strtocert(buf);
+ if(ai->cert == H)
+ goto out;
+
+ /* my secret/public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ mysk = strtosk(buf);
+ ai->mysk = (Keyring_SK*)mysk;
+ if(mysk == H)
+ goto out;
+ sa = checkSigAlg(mysk->x.sa);
+ mypk = newPK(sa, stringdup(mysk->x.owner), 1);
+ mypk->key = (*sa->vec->sk2pk)(mysk->key);
+ ai->mypk = (Keyring_PK*)mypk;
+
+ /* diffie hellman base */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ b = strtomp(buf, nil, 64, nil);
+ ai->alpha = newIPint(b);
+
+ /* diffie hellman modulus */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ b = strtomp(buf, nil, 64, nil);
+ ai->p = newIPint(b);
+ ok = 1;
+out:
+ if(!ok){
+ destroy(*f->ret);
+ *f->ret = H;
+ }
+ free(buf);
+ if(fd >= 0){
+ release();
+ kclose(fd);
+ acquire();
+ kwerrstr("%q: %s", string2c(f->filename), MSG);
+ }
+}
+
+void
+keyringmodinit(void)
+{
+ SigAlgVec *sav;
+ extern SigAlgVec* elgamalinit(void);
+ extern SigAlgVec* rsainit(void);
+ extern SigAlgVec* dsainit(void);
+
+ TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap));
+ TSigAlg = dtype(freeSigAlg, sizeof(SigAlg), SigAlgmap, sizeof(SigAlgmap));
+ TSK = dtype(freeSK, sizeof(SK), SKmap, sizeof(SKmap));
+ TPK = dtype(freePK, sizeof(PK), PKmap, sizeof(PKmap));
+ TCertificate = dtype(freeCertificate, sizeof(Certificate), Certificatemap,
+ sizeof(Certificatemap));
+ TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap,
+ sizeof(DigestStatemap));
+ TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap,
+ sizeof(AESstatemap));
+ TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap,
+ sizeof(DESstatemap));
+ TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap,
+ sizeof(IDEAstatemap));
+ TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap,
+ sizeof(RC4statemap));
+ TAuthinfo = dtype(freeheap, sizeof(Keyring_Authinfo), Authinfomap, sizeof(Authinfomap));
+
+ if((sav = elgamalinit()) != nil)
+ algs[nalg++] = sav;
+ if((sav = rsainit()) != nil)
+ algs[nalg++] = sav;
+ if((sav = dsainit()) != nil)
+ algs[nalg++] = sav;
+
+ fmtinstall('U', big64conv);
+ builtinmod("$Keyring", Keyringmodtab, Keyringmodlen);
+}
+
+/*
+ * IO on a delimited channel. A message starting with 0x00 is a normal
+ * message. One starting with 0xff is an error string.
+ *
+ * return negative number for error messages (including hangup)
+ */
+static int
+getbuf(int fd, uchar *buf, int n, char *err, int nerr)
+{
+ int len;
+
+ release();
+ len = kread(fd, buf, n);
+ acquire();
+ if(len <= 0){
+ strncpy(err, "hungup", nerr);
+ buf[nerr-1] = 0;
+ return -1;
+ }
+ if(buf[0] == 0)
+ return len-1;
+ if(buf[0] != 0xff){
+ /*
+ * this happens when the client's password is wrong: both sides use a digest of the
+ * password as a crypt key for devssl. When they don't match decryption garbles
+ * messages
+ */
+ strncpy(err, "failure", nerr);
+ err[nerr-1] = 0;
+ return -1;
+ }
+
+ /* error string */
+ len--;
+ if(len < 1){
+ strncpy(err, "unknown", nerr);
+ err[nerr-1] = 0;
+ } else {
+ if(len >= nerr)
+ len = nerr-1;
+ memmove(err, buf+1, len);
+ err[len] = 0;
+ }
+ return -1;
+}
+
+void
+Keyring_getstring(void *fp)
+{
+ F_Keyring_getstring *f;
+ uchar *buf;
+ char err[64];
+ int n;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->fd == H)
+ return;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return;
+
+ n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+ if(n < 0)
+ retnstr(err, strlen(err), &f->ret->t1);
+ else
+ retnstr(((char*)buf)+1, n, &f->ret->t0);
+
+ free(buf);
+}
+
+void
+Keyring_getbytearray(void *fp)
+{
+ F_Keyring_getbytearray *f;
+ uchar *buf;
+ char err[64];
+ int n;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->fd == H)
+ return;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return;
+
+ n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+ if(n < 0)
+ retnstr(err, strlen(err), &f->ret->t1);
+ else
+ f->ret->t0 = mem2array(buf+1, n);
+
+ free(buf);
+}
+
+static int
+putbuf(int fd, void *p, int n)
+{
+ char *buf;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return -1;
+
+ release();
+ buf[0] = 0;
+ if(n < 0){
+ buf[0] = 0xff;
+ n = -n;
+ }
+ if(n >= Maxmsg)
+ n = Maxmsg - 1;
+ memmove(buf+1, p, n);
+ n = kwrite(fd, buf, n+1);
+ acquire();
+
+ free(buf);
+ return n;
+}
+
+void
+Keyring_putstring(void *fp)
+{
+ F_Keyring_putstring *f;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->s == H)
+ return;
+ *f->ret = putbuf(f->fd->fd, string2c(f->s), strlen(string2c(f->s)));
+}
+
+void
+Keyring_puterror(void *fp)
+{
+ F_Keyring_puterror *f;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->s == H)
+ return;
+ *f->ret = putbuf(f->fd->fd, string2c(f->s), -strlen(string2c(f->s)));
+}
+
+void
+Keyring_putbytearray(void *fp)
+{
+ F_Keyring_putbytearray *f;
+ int n;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->a == H)
+ return;
+ n = f->n;
+ if(n > f->a->len)
+ n = f->a->len;
+ *f->ret = putbuf(f->fd->fd, f->a->data, n);
+}
+
+void
+Keyring_dessetup(void *fp)
+{
+ F_Keyring_dessetup *f;
+ Heap *h;
+ XDESstate *ds;
+ uchar *ivec;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->key == (Array*)H)
+ return;
+ if(f->ivec == (Array*)H)
+ ivec = 0;
+ else
+ ivec = f->ivec->data;
+
+ if(f->key->len < 8 || (ivec && f->ivec->len < 8))
+ return;
+
+ h = heap(TDESstate);
+ ds = H2D(XDESstate*, h);
+ setupDESstate(&ds->state, f->key->data, ivec);
+
+ *f->ret = (Keyring_DESstate*)ds;
+}
+
+void
+Keyring_desecb(void *fp)
+{
+ F_Keyring_desecb *f;
+ XDESstate *ds;
+ int i;
+ uchar *p;
+ /* uchar tmp[8]; */
+
+ f = fp;
+
+ if(f->state == (Keyring_DESstate*)H)
+ return;
+ if(f->buf == (Array*)H)
+ return;
+ if(f->buf->len < f->n)
+ f->n = f->buf->len;
+ if(f->n & 7)
+ return;
+
+ ds = (XDESstate*)f->state;
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Keyring_descbc(void *fp)
+{
+ F_Keyring_descbc *f;
+ XDESstate *ds;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->state == (Keyring_DESstate*)H)
+ return;
+ if(f->buf == (Array*)H)
+ return;
+ if(f->buf->len < f->n)
+ f->n = f->buf->len;
+ if(f->n & 7)
+ return;
+
+ ds = (XDESstate*)f->state;
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ block_cipher(ds->state.expanded, p, 0);
+ memmove(ds->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ block_cipher(ds->state.expanded, p, 1);
+ p2 = tmp;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Keyring_ideasetup(void *fp)
+{
+ F_Keyring_ideasetup *f;
+ Heap *h;
+ XIDEAstate *is;
+ uchar *ivec;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->key == (Array*)H)
+ return;
+ if(f->ivec == (Array*)H)
+ ivec = 0;
+ else
+ ivec = f->ivec->data;
+
+ if(f->key->len < 16 || (ivec && f->ivec->len < 8))
+ return;
+
+ h = heap(TIDEAstate);
+ is = H2D(XIDEAstate*, h);
+
+ setupIDEAstate(&is->state, f->key->data, ivec);
+
+ *f->ret = (Keyring_IDEAstate*)is;
+}
+
+void
+Keyring_ideaecb(void *fp)
+{
+ F_Keyring_ideaecb *f;
+ XIDEAstate *is;
+ int i;
+ uchar *p;
+ /* uchar tmp[8]; */
+
+ f = fp;
+
+ if(f->state == (Keyring_IDEAstate*)H)
+ return;
+ if(f->buf == (Array*)H)
+ return;
+ if(f->buf->len < f->n)
+ f->n = f->buf->len;
+ if(f->n & 7)
+ return;
+
+ is = (XIDEAstate*)f->state;
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Keyring_ideacbc(void *fp)
+{
+ F_Keyring_ideacbc *f;
+ XIDEAstate *is;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->state == (Keyring_IDEAstate*)H)
+ return;
+ if(f->buf == (Array*)H)
+ return;
+ if(f->buf->len < f->n)
+ f->n = f->buf->len;
+ if(f->n & 7)
+ return;
+
+ is = (XIDEAstate*)f->state;
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ idea_cipher(is->state.edkey, p, 0);
+ memmove(is->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ idea_cipher(is->state.edkey, p, 1);
+ p2 = tmp;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Keyring_aessetup(void *fp)
+{
+ F_Keyring_aessetup *f;
+ Heap *h;
+ XAESstate *is;
+ uchar *ivec;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->key == (Array*)H)
+ return;
+ if(f->ivec == (Array*)H)
+ ivec = nil;
+ else
+ ivec = f->ivec->data;
+
+ if(f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+ return;
+ if(ivec && f->ivec->len < AESbsize)
+ return;
+
+ h = heap(TAESstate);
+ is = H2D(XAESstate*, h);
+
+ setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Keyring_AESstate*)is;
+}
+
+void
+Keyring_aescbc(void *fp)
+{
+ F_Keyring_aescbc *f;
+ XAESstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->state == (Keyring_AESstate*)H)
+ return;
+ if(f->buf == (Array*)H)
+ return;
+ if(f->buf->len < f->n)
+ f->n = f->buf->len;
+
+ is = (XAESstate*)f->state;
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ aesCBCencrypt(p, f->n, &is->state);
+ else
+ aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_rc4setup(void *fp)
+{
+ F_Keyring_rc4setup *f;
+ Heap *h;
+ XRC4state *is;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->seed == (Array*)H)
+ return;
+
+ h = heap(TRC4state);
+ is = H2D(XRC4state*, h);
+
+ setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+ *f->ret = (Keyring_RC4state*)is;
+}
+
+void
+Keyring_rc4(void *fp)
+{
+ F_Keyring_rc4 *f;
+ XRC4state *is;
+ uchar *p;
+
+ f = fp;
+ if(f->state == (Keyring_RC4state*)H)
+ return;
+ if(f->buf == (Array*)H)
+ return;
+ if(f->buf->len < f->n)
+ f->n = f->buf->len;
+ is = (XRC4state*)f->state;
+ p = f->buf->data;
+ rc4(&is->state, p, f->n);
+}
+
+void
+Keyring_rc4skip(void *fp)
+{
+ F_Keyring_rc4skip *f;
+ XRC4state *is;
+
+ f = fp;
+ if(f->state == (Keyring_RC4state*)H)
+ return;
+ is = (XRC4state*)f->state;
+ rc4skip(&is->state, f->n);
+}
+
+void
+Keyring_rc4back(void *fp)
+{
+ F_Keyring_rc4back *f;
+ XRC4state *is;
+
+ f = fp;
+ if(f->state == (Keyring_RC4state*)H)
+ return;
+ is = (XRC4state*)f->state;
+ rc4back(&is->state, f->n);
+}
diff --git a/libinterp/keyring.h b/libinterp/keyring.h
new file mode 100644
index 00000000..f62ac800
--- /dev/null
+++ b/libinterp/keyring.h
@@ -0,0 +1,75 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Keyringmodtab[]={
+ "IPint.add",0xa47c1b24,IPint_add,40,2,{0x0,0xc0,},
+ "aescbc",0xac616ba,Keyring_aescbc,48,2,{0x0,0xc0,},
+ "aessetup",0x44452583,Keyring_aessetup,40,2,{0x0,0xc0,},
+ "auth",0x9c576bb,Keyring_auth,48,2,{0x0,0xc0,},
+ "IPint.b64toip",0xa803ee03,IPint_b64toip,40,2,{0x0,0x80,},
+ "IPint.bebytestoip",0x6fa90725,IPint_bebytestoip,40,2,{0x0,0x80,},
+ "IPint.bits",0xeb4c9bad,IPint_bits,40,2,{0x0,0x80,},
+ "IPint.bytestoip",0x6fa90725,IPint_bytestoip,40,2,{0x0,0x80,},
+ "certtoattr",0xbc65254a,Keyring_certtoattr,40,2,{0x0,0x80,},
+ "certtostr",0xbc65254a,Keyring_certtostr,40,2,{0x0,0x80,},
+ "IPint.cmp",0x79774f9e,IPint_cmp,40,2,{0x0,0xc0,},
+ "IPint.copy",0x491fbd11,IPint_copy,40,2,{0x0,0x80,},
+ "DigestState.copy",0x491fbd11,DigestState_copy,40,2,{0x0,0x80,},
+ "descbc",0xac616ba,Keyring_descbc,48,2,{0x0,0xc0,},
+ "desecb",0xac616ba,Keyring_desecb,48,2,{0x0,0xc0,},
+ "dessetup",0x44452583,Keyring_dessetup,40,2,{0x0,0xc0,},
+ "dhparams",0x6abb2418,Keyring_dhparams,40,0,{0},
+ "IPint.div",0x4672bf61,IPint_div,40,2,{0x0,0xc0,},
+ "IPint.eq",0x79774f9e,IPint_eq,40,2,{0x0,0xc0,},
+ "IPint.expmod",0xe6105024,IPint_expmod,48,2,{0x0,0xe0,},
+ "genSK",0xadd8cbd9,Keyring_genSK,48,2,{0x0,0xc0,},
+ "genSKfromPK",0x5416d1ee,Keyring_genSKfromPK,40,2,{0x0,0xc0,},
+ "getbytearray",0x4e02ce80,Keyring_getbytearray,40,2,{0x0,0x80,},
+ "getmsg",0xd9de1bb7,Keyring_getmsg,40,2,{0x0,0x80,},
+ "getstring",0x92f10e56,Keyring_getstring,40,2,{0x0,0x80,},
+ "hmac_md5",0xec9ac159,Keyring_hmac_md5,56,2,{0x0,0xb8,},
+ "hmac_sha1",0xec9ac159,Keyring_hmac_sha1,56,2,{0x0,0xb8,},
+ "ideacbc",0xac616ba,Keyring_ideacbc,48,2,{0x0,0xc0,},
+ "ideaecb",0xac616ba,Keyring_ideaecb,48,2,{0x0,0xc0,},
+ "ideasetup",0x44452583,Keyring_ideasetup,40,2,{0x0,0xc0,},
+ "IPint.inttoip",0x95dc8b6d,IPint_inttoip,40,0,{0},
+ "IPint.invert",0xa47c1b24,IPint_invert,40,2,{0x0,0xc0,},
+ "IPint.iptob64",0xfab4eb8a,IPint_iptob64,40,2,{0x0,0x80,},
+ "IPint.iptobebytes",0xc8e5162d,IPint_iptobebytes,40,2,{0x0,0x80,},
+ "IPint.iptobytes",0xc8e5162d,IPint_iptobytes,40,2,{0x0,0x80,},
+ "IPint.iptoint",0xeb4c9bad,IPint_iptoint,40,2,{0x0,0x80,},
+ "IPint.iptostr",0xf9fdc03d,IPint_iptostr,40,2,{0x0,0x80,},
+ "md4",0x7656377,Keyring_md4,48,2,{0x0,0xb0,},
+ "md5",0x7656377,Keyring_md5,48,2,{0x0,0xb0,},
+ "IPint.mul",0xa47c1b24,IPint_mul,40,2,{0x0,0xc0,},
+ "IPint.neg",0x491fbd11,IPint_neg,40,2,{0x0,0x80,},
+ "pktoattr",0xfb4e61ba,Keyring_pktoattr,40,2,{0x0,0x80,},
+ "pktostr",0xfb4e61ba,Keyring_pktostr,40,2,{0x0,0x80,},
+ "putbytearray",0x7cfef557,Keyring_putbytearray,48,2,{0x0,0xc0,},
+ "puterror",0xd2526222,Keyring_puterror,40,2,{0x0,0xc0,},
+ "putstring",0xd2526222,Keyring_putstring,40,2,{0x0,0xc0,},
+ "IPint.random",0x70bcd6f1,IPint_random,40,0,{0},
+ "rc4",0xd051c505,Keyring_rc4,48,2,{0x0,0xc0,},
+ "rc4back",0x3643caf7,Keyring_rc4back,40,2,{0x0,0x80,},
+ "rc4setup",0x6fa90725,Keyring_rc4setup,40,2,{0x0,0x80,},
+ "rc4skip",0x3643caf7,Keyring_rc4skip,40,2,{0x0,0x80,},
+ "readauthinfo",0xb2c82015,Keyring_readauthinfo,40,2,{0x0,0x80,},
+ "senderrmsg",0xd2526222,Keyring_senderrmsg,40,2,{0x0,0xc0,},
+ "sendmsg",0x7cfef557,Keyring_sendmsg,48,2,{0x0,0xc0,},
+ "sha1",0x7656377,Keyring_sha1,48,2,{0x0,0xb0,},
+ "IPint.shl",0xc7b0bc01,IPint_shl,40,2,{0x0,0x80,},
+ "IPint.shr",0xc7b0bc01,IPint_shr,40,2,{0x0,0x80,},
+ "sign",0xdacb7a7e,Keyring_sign,48,2,{0x0,0xb0,},
+ "signm",0xba5bd10f,Keyring_signm,48,2,{0x0,0xe0,},
+ "sktoattr",0xfb4e61ba,Keyring_sktoattr,40,2,{0x0,0x80,},
+ "sktopk",0x6f74c7c9,Keyring_sktopk,40,2,{0x0,0x80,},
+ "sktostr",0xfb4e61ba,Keyring_sktostr,40,2,{0x0,0x80,},
+ "strtocert",0x2c0ee68a,Keyring_strtocert,40,2,{0x0,0x80,},
+ "IPint.strtoip",0x12d7a943,IPint_strtoip,40,2,{0x0,0x80,},
+ "strtopk",0xcc511522,Keyring_strtopk,40,2,{0x0,0x80,},
+ "strtosk",0xcc511522,Keyring_strtosk,40,2,{0x0,0x80,},
+ "IPint.sub",0xa47c1b24,IPint_sub,40,2,{0x0,0xc0,},
+ "verify",0x8b5b9f76,Keyring_verify,48,2,{0x0,0xe0,},
+ "verifym",0x8b5b9f76,Keyring_verifym,48,2,{0x0,0xe0,},
+ "writeauthinfo",0x5ba03002,Keyring_writeauthinfo,40,2,{0x0,0xc0,},
+ 0
+};
+#define Keyringmodlen 70
diff --git a/libinterp/link.c b/libinterp/link.c
new file mode 100644
index 00000000..87756122
--- /dev/null
+++ b/libinterp/link.c
@@ -0,0 +1,132 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <kernel.h>
+
+static void
+newlink(Link *l, char *fn, int sig, Type *t)
+{
+ l->name = malloc(strlen(fn)+1);
+ if(l->name == nil)
+ error(exNomem);
+ strcpy(l->name, fn);
+ l->sig = sig;
+ l->frame = t;
+}
+
+void
+runtime(Module *m, Link *l, char *fn, int sig, void (*runt)(void*), Type *t)
+{
+ USED(m);
+ newlink(l, fn, sig, t);
+ l->u.runt = runt;
+}
+
+void
+mlink(Module *m, Link* l, uchar *fn, int sig, int pc, Type *t)
+{
+ newlink(l, (char*)fn, sig, t);
+ l->u.pc = m->prog+pc;
+}
+
+static int
+linkm(Module *m, Modlink *ml, int i, Import *ldt)
+{
+ Link *l;
+ int sig;
+ char e[ERRMAX];
+
+ sig = ldt->sig;
+ for(l = m->ext; l->name; l++)
+ if(strcmp(ldt->name, l->name) == 0)
+ break;
+
+ if(l == nil) {
+ snprint(e, sizeof(e), "link failed fn %s->%s() not implemented", m->name, ldt->name);
+ goto bad;
+ }
+ if(l->sig != sig) {
+ snprint(e, sizeof(e), "link typecheck %s->%s() %ux/%ux",
+ m->name, ldt->name, l->sig, sig);
+ goto bad;
+ }
+
+ ml->links[i].u = l->u;
+ ml->links[i].frame = l->frame;
+ return 0;
+bad:
+ kwerrstr(e);
+ print("%s\n", e);
+ return -1;
+}
+
+Modlink*
+mklinkmod(Module *m, int n)
+{
+ Heap *h;
+ Modlink *ml;
+
+ h = nheap(sizeof(Modlink)+(n-1)*sizeof(ml->links[0]));
+ h->t = &Tmodlink;
+ Tmodlink.ref++;
+ ml = H2D(Modlink*, h);
+ ml->nlinks = n;
+ ml->m = m;
+ ml->prog = m->prog;
+ ml->type = m->type;
+ ml->compiled = m->compiled;
+ ml->MP = H;
+ ml->data = nil;
+
+ return ml;
+}
+
+Modlink*
+linkmod(Module *m, Import *ldt, int mkmp)
+{
+ Type *t;
+ Heap *h;
+ int i;
+ Modlink *ml;
+ Import *l;
+
+ if(m == nil)
+ return H;
+
+ for(i = 0, l = ldt; l->name != nil; i++, l++)
+ ;
+ ml = mklinkmod(m, i);
+
+ if(mkmp){
+ if(m->rt == DYNMOD)
+ newdyndata(ml);
+ else if(mkmp && m->origmp != H && m->ntype > 0) {
+ t = m->type[0];
+ h = nheap(t->size);
+ h->t = t;
+ t->ref++;
+ ml->MP = H2D(uchar*, h);
+ newmp(ml->MP, m->origmp, t);
+ }
+ }
+
+ for(i = 0, l = ldt; l->name != nil; i++, l++) {
+ if(linkm(m, ml, i, l) < 0){
+ destroy(ml);
+ return H;
+ }
+ }
+
+ return ml;
+}
+
+void
+destroylinks(Module *m)
+{
+ Link *l;
+
+ for(l = m->ext; l->name; l++)
+ free(l->name);
+ free(m->ext);
+}
diff --git a/libinterp/load.c b/libinterp/load.c
new file mode 100644
index 00000000..8645338a
--- /dev/null
+++ b/libinterp/load.c
@@ -0,0 +1,638 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <kernel.h>
+
+#define A(r) *((Array**)(r))
+
+Module* modules;
+int dontcompile;
+
+static int
+operand(uchar **p)
+{
+ int c;
+ uchar *cp;
+
+ cp = *p;
+ c = cp[0];
+ switch(c & 0xC0) {
+ case 0x00:
+ *p = cp+1;
+ return c;
+ case 0x40:
+ *p = cp+1;
+ return c|~0x7F;
+ case 0x80:
+ *p = cp+2;
+ if(c & 0x20)
+ c |= ~0x3F;
+ else
+ c &= 0x3F;
+ return (c<<8)|cp[1];
+ case 0xC0:
+ *p = cp+4;
+ if(c & 0x20)
+ c |= ~0x3F;
+ else
+ c &= 0x3F;
+ return (c<<24)|(cp[1]<<16)|(cp[2]<<8)|cp[3];
+ }
+ return 0;
+}
+
+static ulong
+disw(uchar **p)
+{
+ ulong v;
+ uchar *c;
+
+ c = *p;
+ v = c[0] << 24;
+ v |= c[1] << 16;
+ v |= c[2] << 8;
+ v |= c[3];
+ *p = c + 4;
+ return v;
+}
+
+double
+canontod(ulong v[2])
+{
+ union { double d; unsigned long ul[2]; } a;
+ a.d = 1.;
+ if(a.ul[0]) {
+ a.ul[0] = v[0];
+ a.ul[1] = v[1];
+ }
+ else {
+ a.ul[1] = v[0];
+ a.ul[0] = v[1];
+ }
+ return a.d;
+}
+
+Module*
+load(char *path)
+{
+ return readmod(path, nil, 0);
+}
+
+Type*
+dtype(void (*destroy)(Heap*, int), int size, uchar *map, int mapsize)
+{
+ Type *t;
+
+ t = malloc(sizeof(Type)+mapsize);
+ if(t != nil) {
+ t->ref = 1;
+ t->free = destroy;
+ t->mark = markheap;
+ t->size = size;
+ t->np = mapsize;
+ memmove(t->map, map, mapsize);
+ }
+ return t;
+}
+
+int
+brpatch(Inst *ip, Module *m)
+{
+ switch(ip->op) {
+ case ICALL:
+ case IJMP:
+ case IBEQW:
+ case IBNEW:
+ case IBLTW:
+ case IBLEW:
+ case IBGTW:
+ case IBGEW:
+ case IBEQB:
+ case IBNEB:
+ case IBLTB:
+ case IBLEB:
+ case IBGTB:
+ case IBGEB:
+ case IBEQF:
+ case IBNEF:
+ case IBLTF:
+ case IBLEF:
+ case IBGTF:
+ case IBGEF:
+ case IBEQC:
+ case IBNEC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ case IBEQL:
+ case IBNEL:
+ case IBLTL:
+ case IBLEL:
+ case IBGTL:
+ case IBGEL:
+ case ISPAWN:
+ if(ip->d.imm < 0 || ip->d.imm >= m->nprog)
+ return 0;
+ ip->d.imm = (WORD)&m->prog[ip->d.imm];
+ break;
+ }
+ return 1;
+}
+
+Module*
+parsemod(char *path, uchar *code, ulong length, Dir *dir)
+{
+ Heap *h;
+ Inst *ip;
+ Type *pt;
+ String *s;
+ Module *m;
+ Array *ary;
+ ulong ul[2];
+ WORD lo, hi;
+ int lsize, id, v, entry, entryt, tnp, tsz, siglen;
+ int de, pc, i, n, isize, dsize, hsize, dasp;
+ uchar *mod, sm, *istream, **isp, *si, *addr, *dastack[DADEPTH];
+ Link *l;
+
+ istream = code;
+ isp = &istream;
+
+ m = malloc(sizeof(Module));
+ if(m == nil)
+ return nil;
+
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->origmp = H;
+ m->pctab = nil;
+
+ switch(operand(isp)) {
+ default:
+ kwerrstr("bad magic");
+ goto bad;
+ case SMAGIC:
+ siglen = operand(isp);
+ n = length-(*isp-code);
+ if(n < 0 || siglen > n){
+ kwerrstr("corrupt signature");
+ goto bad;
+ }
+ if(verifysigner(*isp, siglen, *isp+siglen, n-siglen) == 0) {
+ kwerrstr("security violation");
+ goto bad;
+ }
+ *isp += siglen;
+ break;
+ case XMAGIC:
+ if(mustbesigned(path, code, length, dir)){
+ kwerrstr("security violation: not signed");
+ goto bad;
+ }
+ break;
+ }
+
+ m->rt = operand(isp);
+ m->ss = operand(isp);
+ isize = operand(isp);
+ dsize = operand(isp);
+ hsize = operand(isp);
+ lsize = operand(isp);
+ entry = operand(isp);
+ entryt = operand(isp);
+
+ if(isize < 0 || dsize < 0 || hsize < 0 || lsize < 0) {
+ kwerrstr("implausible Dis file");
+ goto bad;
+ }
+
+ m->nprog = isize;
+ m->prog = mallocz(isize*sizeof(Inst), 0);
+ if(m->prog == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+
+ m->ref = 1;
+
+ ip = m->prog;
+ for(i = 0; i < isize; i++) {
+ ip->op = *istream++;
+ ip->add = *istream++;
+ ip->reg = 0;
+ ip->s.imm = 0;
+ ip->d.imm = 0;
+ switch(ip->add & ARM) {
+ case AXIMM:
+ case AXINF:
+ case AXINM:
+ ip->reg = operand(isp);
+ break;
+ }
+ switch(UXSRC(ip->add)) {
+ case SRC(AFP):
+ case SRC(AMP):
+ case SRC(AIMM):
+ ip->s.ind = operand(isp);
+ break;
+ case SRC(AIND|AFP):
+ case SRC(AIND|AMP):
+ ip->s.i.f = operand(isp);
+ ip->s.i.s = operand(isp);
+ break;
+ }
+ switch(UXDST(ip->add)) {
+ case DST(AFP):
+ case DST(AMP):
+ ip->d.ind = operand(isp);
+ break;
+ case DST(AIMM):
+ ip->d.ind = operand(isp);
+ if(brpatch(ip, m) == 0) {
+ kwerrstr("bad branch addr");
+ goto bad;
+ }
+ break;
+ case DST(AIND|AFP):
+ case DST(AIND|AMP):
+ ip->d.i.f = operand(isp);
+ ip->d.i.s = operand(isp);
+ break;
+ }
+ ip++;
+ }
+
+ m->ntype = hsize;
+ m->type = malloc(hsize*sizeof(Type*));
+ if(m->type == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(i = 0; i < hsize; i++) {
+ id = operand(isp);
+ if(id > hsize) {
+ kwerrstr("heap id range");
+ goto bad;
+ }
+ tsz = operand(isp);
+ tnp = operand(isp);
+ if(tsz < 0 || tnp < 0 || tnp > 128*1024){
+ kwerrstr("implausible Dis file");
+ goto bad;
+ }
+ pt = dtype(freeheap, tsz, istream, tnp);
+ if(pt == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ istream += tnp;
+ m->type[id] = pt;
+ }
+
+ if(dsize != 0) {
+ pt = m->type[0];
+ if(pt == 0 || pt->size != dsize) {
+ kwerrstr("bad desc for mp");
+ goto bad;
+ }
+ h = heapz(pt);
+ m->origmp = H2D(uchar*, h);
+ }
+ addr = m->origmp;
+ dasp = 0;
+ for(;;) {
+ sm = *istream++;
+ if(sm == 0)
+ break;
+ n = DLEN(sm);
+ if(n == 0)
+ n = operand(isp);
+ v = operand(isp);
+ si = addr + v;
+ switch(DTYPE(sm)) {
+ default:
+ kwerrstr("bad data item");
+ goto bad;
+ case DEFS:
+ s = c2string((char*)istream, n);
+ istream += n;
+ *(String**)si = s;
+ break;
+ case DEFB:
+ for(i = 0; i < n; i++)
+ *si++ = *istream++;
+ break;
+ case DEFW:
+ for(i = 0; i < n; i++) {
+ *(WORD*)si = disw(isp);
+ si += sizeof(WORD);
+ }
+ break;
+ case DEFL:
+ for(i = 0; i < n; i++) {
+ hi = disw(isp);
+ lo = disw(isp);
+ *(LONG*)si = (LONG)hi << 32 | (LONG)(ulong)lo;
+ si += sizeof(LONG);
+ }
+ break;
+ case DEFF:
+ for(i = 0; i < n; i++) {
+ ul[0] = disw(isp);
+ ul[1] = disw(isp);
+ *(REAL*)si = canontod(ul);
+ si += sizeof(REAL);
+ }
+ break;
+ case DEFA: /* Array */
+ v = disw(isp);
+ if(v < 0 || v > m->ntype) {
+ kwerrstr("bad array type");
+ goto bad;
+ }
+ pt = m->type[v];
+ v = disw(isp);
+ h = nheap(sizeof(Array)+(pt->size*v));
+ h->t = &Tarray;
+ h->t->ref++;
+ ary = H2D(Array*, h);
+ ary->t = pt;
+ ary->len = v;
+ ary->root = H;
+ ary->data = (uchar*)ary+sizeof(Array);
+ memset((void*)ary->data, 0, pt->size*v);
+ initarray(pt, ary);
+ A(si) = ary;
+ break;
+ case DIND: /* Set index */
+ ary = A(si);
+ if(ary == H || D2H(ary)->t != &Tarray) {
+ kwerrstr("ind not array");
+ goto bad;
+ }
+ v = disw(isp);
+ if(v > ary->len || v < 0 || dasp >= DADEPTH) {
+ kwerrstr("array init range");
+ goto bad;
+ }
+ dastack[dasp++] = addr;
+ addr = ary->data+v*ary->t->size;
+ break;
+ case DAPOP:
+ if(dasp == 0) {
+ kwerrstr("pop range");
+ goto bad;
+ }
+ addr = dastack[--dasp];
+ break;
+ }
+ }
+ mod = istream;
+ if(memchr(mod, 0, 128) == 0) {
+ kwerrstr("bad module name");
+ goto bad;
+ }
+ m->name = strdup((char*)mod);
+ if(m->name == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ while(*istream++)
+ ;
+
+ l = m->ext = (Link*)malloc((lsize+1)*sizeof(Link));
+ if(l == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(i = 0; i < lsize; i++, l++) {
+ pc = operand(isp);
+ de = operand(isp);
+ v = disw(isp);
+ pt = nil;
+ if(de != -1)
+ pt = m->type[de];
+ mlink(m, l, istream, v, pc, pt);
+ while(*istream++)
+ ;
+ }
+ l->name = nil;
+
+ if(m->rt & HASLDT0){
+ kwerrstr("obsolete dis");
+ goto bad;
+ }
+
+ if(m->rt & HASLDT){
+ int j, nl;
+ Import *i1, **i2;
+
+ nl = operand(isp);
+ i2 = m->ldt = (Import**)malloc((nl+1)*sizeof(Import*));
+ if(i2 == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(i = 0; i < nl; i++, i2++){
+ n = operand(isp);
+ i1 = *i2 = (Import*)malloc((n+1)*sizeof(Import));
+ if(i1 == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(j = 0; j < n; j++, i1++){
+ i1->sig = disw(isp);
+ i1->name = strdup((char*)istream);
+ if(i1->name == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ while(*istream++)
+ ;
+ }
+ }
+ istream++;
+ }
+
+ if(m->rt & HASEXCEPT){
+ int j, nh;
+ Handler *h;
+ Except *e;
+
+ nh = operand(isp);
+ m->htab = malloc((nh+1)*sizeof(Handler));
+ if(m->htab == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ h = m->htab;
+ for(i = 0; i < nh; i++, h++){
+ h->eoff = operand(isp);
+ h->pc1 = operand(isp);
+ h->pc2 = operand(isp);
+ n = operand(isp);
+ if(n != -1)
+ h->t = m->type[n];
+ n = operand(isp);
+ h->ne = n>>16;
+ n &= 0xffff;
+ h->etab = malloc((n+1)*sizeof(Except));
+ if(h->etab == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ e = h->etab;
+ for(j = 0; j < n; j++, e++){
+ e->s = strdup((char*)istream);
+ if(e->s == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ while(*istream++)
+ ;
+ e->pc = operand(isp);
+ }
+ e->s = nil;
+ e->pc = operand(isp);
+ }
+ istream++;
+ }
+
+ m->entryt = nil;
+ m->entry = m->prog;
+ if((ulong)entry < isize && (ulong)entryt < hsize) {
+ m->entry = &m->prog[entry];
+ m->entryt = m->type[entryt];
+ }
+
+ if(cflag) {
+ if((m->rt&DONTCOMPILE) == 0 && !dontcompile)
+ compile(m, isize, nil);
+ }
+ else
+ if(m->rt & MUSTCOMPILE && !dontcompile) {
+ if(compile(m, isize, nil) == 0) {
+ kwerrstr("compiler required");
+ goto bad;
+ }
+ }
+
+ m->path = strdup(path);
+ if(m->path == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ m->link = modules;
+ modules = m;
+
+ return m;
+bad:
+ destroy(m->origmp);
+ freemod(m);
+ return nil;
+}
+
+Module*
+newmod(char *s)
+{
+ Module *m;
+
+ m = malloc(sizeof(Module));
+ if(m == nil)
+ error(exNomem);
+ m->ref = 1;
+ m->path = s;
+ m->origmp = H;
+ m->name = strdup(s);
+ if(m->name == nil) {
+ free(m);
+ error(exNomem);
+ }
+ m->link = modules;
+ modules = m;
+ m->pctab = nil;
+ return m;
+}
+
+Module*
+lookmod(char *s)
+{
+ Module *m;
+
+ for(m = modules; m != nil; m = m->link)
+ if(strcmp(s, m->path) == 0) {
+ m->ref++;
+ return m;
+ }
+ return nil;
+}
+
+void
+freemod(Module *m)
+{
+ int i;
+ Handler *h;
+ Except *e;
+ Import *i1, **i2;
+
+ if(m->type != nil) {
+ for(i = 0; i < m->ntype; i++)
+ freetype(m->type[i]);
+ free(m->type);
+ }
+ free(m->name);
+ free(m->prog);
+ free(m->path);
+ free(m->pctab);
+ if(m->ldt != nil){
+ for(i2 = m->ldt; *i2 != nil; i2++){
+ for(i1 = *i2; i1->name != nil; i1++)
+ free(i1->name);
+ free(*i2);
+ }
+ free(m->ldt);
+ }
+ if(m->htab != nil){
+ for(h = m->htab; h->etab != nil; h++){
+ for(e = h->etab; e->s != nil; e++)
+ free(e->s);
+ free(h->etab);
+ }
+ free(m->htab);
+ }
+ free(m);
+}
+
+void
+unload(Module *m)
+{
+ Module **last, *mm;
+
+ m->ref--;
+ if(m->ref > 0)
+ return;
+ if(m->ref == -1)
+ abort();
+
+ last = &modules;
+ for(mm = modules; mm != nil; mm = mm->link) {
+ if(mm == m) {
+ *last = m->link;
+ break;
+ }
+ last = &mm->link;
+ }
+
+ if(m->rt == DYNMOD)
+ freedyncode(m);
+ else
+ destroy(m->origmp);
+
+ destroylinks(m);
+
+ freemod(m);
+}
diff --git a/libinterp/loader.c b/libinterp/loader.c
new file mode 100644
index 00000000..3de66c7e
--- /dev/null
+++ b/libinterp/loader.c
@@ -0,0 +1,444 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "runt.h"
+#include "loadermod.h"
+#include "raise.h"
+#include <kernel.h>
+
+static uchar Instmap[] = Loader_Inst_map;
+static Type* Tinst;
+static uchar Tdescmap[] = Loader_Typedesc_map;
+static Type* Tdesc;
+static uchar Tlinkmap[] = Loader_Link_map;
+static Type* Tlink;
+
+void
+loadermodinit(void)
+{
+ sysinit();
+ builtinmod("$Loader", Loadermodtab, Loadermodlen);
+ Tinst = dtype(freeheap, sizeof(Loader_Inst), Instmap, sizeof(Instmap));
+ Tdesc = dtype(freeheap, sizeof(Loader_Typedesc), Tdescmap, sizeof(Tdescmap));
+ Tlink = dtype(freeheap, sizeof(Loader_Link), Tlinkmap, sizeof(Tlinkmap));
+}
+
+static void
+brunpatch(Loader_Inst *ip, Module *m)
+{
+ switch(ip->op) {
+ case ICALL:
+ case IJMP:
+ case IBEQW:
+ case IBNEW:
+ case IBLTW:
+ case IBLEW:
+ case IBGTW:
+ case IBGEW:
+ case IBEQB:
+ case IBNEB:
+ case IBLTB:
+ case IBLEB:
+ case IBGTB:
+ case IBGEB:
+ case IBEQF:
+ case IBNEF:
+ case IBLTF:
+ case IBLEF:
+ case IBGTF:
+ case IBGEF:
+ case IBEQC:
+ case IBNEC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ case IBEQL:
+ case IBNEL:
+ case IBLTL:
+ case IBLEL:
+ case IBGTL:
+ case IBGEL:
+ case ISPAWN:
+ ip->dst = (Inst*)ip->dst - m->prog;
+ break;
+ }
+}
+
+void
+Loader_ifetch(void *a)
+{
+ Heap *h;
+ Array *ar;
+ Module *m;
+ Inst *i, *ie;
+ Loader_Inst *li;
+ F_Loader_ifetch *f;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+ if(m->compiled) {
+ kwerrstr("compiled module");
+ return;
+ }
+
+ h = nheap(sizeof(Array)+m->nprog*sizeof(Loader_Inst));
+ h->t = &Tarray;
+ h->t->ref++;
+ ar = H2D(Array*, h);
+ ar->t = Tinst;
+ Tinst->ref++;
+ ar->len = m->nprog;
+ ar->root = H;
+ ar->data = (uchar*)ar+sizeof(Array);
+
+ li = (Loader_Inst*)ar->data;
+ i = m->prog;
+ ie = i + m->nprog;
+ while(i < ie) {
+ li->op = i->op;
+ li->addr = i->add;
+ li->src = i->s.imm;
+ li->dst = i->d.imm;
+ li->mid = i->reg;
+ if(UDST(i->add) == AIMM)
+ brunpatch(li, m);
+ li++;
+ i++;
+ }
+
+ *f->ret = ar;
+}
+
+void
+Loader_link(void *a)
+{
+ Link *p;
+ Heap *h;
+ Type **t;
+ int nlink;
+ Module *m;
+ Array *ar;
+ Loader_Link *ll;
+ F_Loader_link *f;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+
+ nlink = 0;
+ for(p = m->ext; p->name; p++)
+ nlink++;
+
+ h = nheap(sizeof(Array)+nlink*sizeof(Loader_Link));
+ h->t = &Tarray;
+ h->t->ref++;
+ ar = H2D(Array*, h);
+ ar->t = Tlink;
+ Tlink->ref++;
+ ar->len = nlink;
+ ar->root = H;
+ ar->data = (uchar*)ar+sizeof(Array);
+
+ ll = (Loader_Link*)ar->data + nlink;
+ for(p = m->ext; p->name; p++) {
+ ll--;
+ ll->name = c2string(p->name, strlen(p->name));
+ ll->sig = p->sig;
+ if(m->prog == nil) {
+ ll->pc = -1;
+ ll->tdesc = -1;
+ } else {
+ ll->pc = p->u.pc - m->prog;
+ ll->tdesc = 0;
+ for(t = m->type; *t != p->frame; t++)
+ ll->tdesc++;
+ }
+ }
+
+ *f->ret = ar;
+}
+
+void
+Loader_tdesc(void *a)
+{
+ int i;
+ Heap *h;
+ Type *t;
+ Array *ar;
+ Module *m;
+ F_Loader_tdesc *f;
+ Loader_Typedesc *lt;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+
+ h = nheap(sizeof(Array)+m->ntype*sizeof(Loader_Typedesc));
+ h->t = &Tarray;
+ h->t->ref++;
+ ar = H2D(Array*, h);
+ ar->t = Tdesc;
+ Tdesc->ref++;
+ ar->len = m->ntype;
+ ar->root = H;
+ ar->data = (uchar*)ar+sizeof(Array);
+
+ lt = (Loader_Typedesc*)ar->data;
+ for(i = 0; i < m->ntype; i++) {
+ t = m->type[i];
+ lt->size = t->size;
+ lt->map = H;
+ if(t->np != 0)
+ lt->map = mem2array(t->map, t->np);
+ lt++;
+ }
+
+ *f->ret = ar;
+}
+
+void
+Loader_newmod(void *a)
+{
+ Heap *h;
+ Module *m;
+ Array *ia;
+ Modlink *ml;
+ Inst *i, *ie;
+ Loader_Inst *li;
+ F_Loader_newmod *f;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->inst == H || f->data == H) {
+ kwerrstr("nil parameters");
+ return;
+ }
+ if(f->nlink < 0) {
+ kwerrstr("bad nlink");
+ return;
+ }
+
+ m = malloc(sizeof(Module));
+ if(m == nil) {
+ kwerrstr(exNomem);
+ return;
+ }
+ m->origmp = H;
+ m->ref = 1;
+ m->ss = f->ss;
+ m->name = strdup(string2c(f->name));
+ m->path = strdup(m->name);
+ m->ntype = 1;
+ m->type = malloc(sizeof(Type*));
+ if(m->name == nil || m->path == nil || m->type == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ m->origmp = (uchar*)f->data;
+ h = D2H(f->data);
+ h->ref++;
+ Setmark(h);
+ m->type[0] = h->t;
+ h->t->ref++;
+
+ ia = f->inst;
+ m->nprog = ia->len;
+ m->prog = malloc(m->nprog*sizeof(Inst));
+ if(m->prog == nil)
+ goto bad;
+ i = m->prog;
+ ie = i + m->nprog;
+ li = (Loader_Inst*)ia->data;
+ while(i < ie) {
+ i->op = li->op;
+ i->add = li->addr;
+ i->reg = li->mid;
+ i->s.imm = li->src;
+ i->d.imm = li->dst;
+ if(brpatch(i, m) == 0) {
+ kwerrstr("bad branch addr");
+ goto bad;
+ }
+ i++;
+ li++;
+ }
+ m->entryt = nil;
+ m->entry = m->prog;
+
+ ml = mklinkmod(m, f->nlink);
+ ml->MP = m->origmp;
+ m->origmp = H;
+ m->pctab = nil;
+ *f->ret = ml;
+ return;
+bad:
+ destroy(m->origmp);
+ freemod(m);
+}
+
+void
+Loader_tnew(void *a)
+{
+ int mem;
+ Module *m;
+ Type *t, **nt;
+ Array *ar, az;
+ F_Loader_tnew *f;
+
+ f = a;
+ *f->ret = -1;
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+ if(m->origmp != H){
+ kwerrstr("need newmod");
+ return;
+ }
+
+ ar = f->map;
+ if(ar == H) {
+ ar = &az;
+ ar->len = 0;
+ ar->data = nil;
+ }
+
+ t = dtype(freeheap, f->size, ar->data, ar->len);
+ if(t == nil)
+ return;
+
+ mem = (m->ntype+1)*sizeof(Type*);
+ if(msize(m->type) > mem) {
+ *f->ret = m->ntype;
+ m->type[m->ntype++] = t;
+ return;
+ }
+ nt = realloc(m->type, mem);
+ if(nt == nil) {
+ kwerrstr(exNomem);
+ return;
+ }
+ m->type = nt;
+ f->mp->type = nt;
+ *f->ret = m->ntype;
+ m->type[m->ntype++] = t;
+}
+
+void
+Loader_ext(void *a)
+{
+ Modl *l;
+ Module *m;
+ Modlink *ml;
+ F_Loader_ext *f;
+
+ f = a;
+ *f->ret = -1;
+ if(f->mp == H) {
+ kwerrstr("nil mp");
+ return;
+ }
+ ml = f->mp;
+ m = ml->m;
+ if(f->tdesc < 0 || f->tdesc >= m->ntype) {
+ kwerrstr("bad tdesc");
+ return;
+ }
+ if(f->pc < 0 || f->pc >= m->nprog) {
+ kwerrstr("bad pc");
+ return;
+ }
+ if(f->idx < 0 || f->idx >= ml->nlinks) {
+ kwerrstr("bad idx");
+ return;
+ }
+ l = &ml->links[f->idx];
+ l->u.pc = m->prog + f->pc;
+ l->frame = m->type[f->tdesc];
+ *f->ret = 0;
+}
+
+void
+Loader_dnew(void *a)
+{
+ F_Loader_dnew *f;
+ Heap *h;
+ Array *ar, az;
+ Type *t;
+
+ f = a;
+ *f->ret = H;
+ if(f->map == H)
+ return;
+ ar = f->map;
+ if(ar == H) {
+ ar = &az;
+ ar->len = 0;
+ ar->data = nil;
+ }
+ t = dtype(freeheap, f->size, ar->data, ar->len);
+ if(t == nil) {
+ kwerrstr(exNomem);
+ return;
+ }
+
+ h=heapz(t);
+ if(h == nil) {
+ freetype(t);
+ kwerrstr(exNomem);
+ return;
+ }
+
+ *f->ret=H2D(Loader_Niladt*, h);
+}
+
+void
+Loader_compile(void *a)
+{
+ Module *m;
+ F_Loader_compile *f;
+
+ f = a;
+ *f->ret = -1;
+ if(f->mp == H) {
+ kwerrstr("nil mp");
+ return;
+ }
+ m = f->mp->m;
+ if(m->compiled) {
+ kwerrstr("compiled module");
+ return;
+ }
+ *f->ret = 0;
+ m->origmp = f->mp->MP;
+ if(cflag || f->flag)
+ if(compile(m, m->nprog, f->mp)) {
+ f->mp->prog = m->prog;
+ f->mp->compiled = 1;
+ } else
+ *f->ret = -1;
+ m->origmp = H;
+}
diff --git a/libinterp/loadermod.h b/libinterp/loadermod.h
new file mode 100644
index 00000000..f8391e1a
--- /dev/null
+++ b/libinterp/loadermod.h
@@ -0,0 +1,13 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Loadermodtab[]={
+ "compile",0x9af56bb1,Loader_compile,40,2,{0x0,0x80,},
+ "dnew",0x62a7cf80,Loader_dnew,40,2,{0x0,0x40,},
+ "ext",0xcd936c80,Loader_ext,48,2,{0x0,0x80,},
+ "ifetch",0xfb64be19,Loader_ifetch,40,2,{0x0,0x80,},
+ "link",0xe2473595,Loader_link,40,2,{0x0,0x80,},
+ "newmod",0x6de26f71,Loader_newmod,56,2,{0x0,0x98,},
+ "tdesc",0xb933ef75,Loader_tdesc,40,2,{0x0,0x80,},
+ "tnew",0xc1d58785,Loader_tnew,48,2,{0x0,0xa0,},
+ 0
+};
+#define Loadermodlen 8
diff --git a/libinterp/math.c b/libinterp/math.c
new file mode 100644
index 00000000..85b2d69e
--- /dev/null
+++ b/libinterp/math.c
@@ -0,0 +1,955 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "mathi.h"
+#include "mathmod.h"
+
+static union
+{
+ double x;
+ uvlong u;
+} bits64;
+
+static union{
+ float x;
+ unsigned int u;
+} bits32;
+
+void
+mathmodinit(void)
+{
+ builtinmod("$Math", Mathmodtab, Mathmodlen);
+ fmtinstall('g', gfltconv);
+ fmtinstall('G', gfltconv);
+ fmtinstall('e', gfltconv);
+ /* fmtinstall('E', gfltconv); */ /* avoid clash with ether address */
+ fmtinstall(0x00c9, gfltconv); /* L'É' */
+ fmtinstall('f', gfltconv);
+}
+
+void
+Math_import_int(void *fp)
+{
+ F_Math_import_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ int *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (int*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ x[i] = u;
+ }
+}
+
+void
+Math_import_real32(void *fp)
+{
+ F_Math_import_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ bits32.u = u;
+ x[i] = bits32.x;
+ }
+}
+
+void
+Math_import_real(void *fp)
+{
+ F_Math_import_int *f;
+ int i, n;
+ uvlong u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=8*n)
+ error(exMathia);
+ bp = f->b->data;
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ bits64.u = u;
+ x[i] = bits64.x;
+ }
+}
+
+void
+Math_export_int(void *fp)
+{
+ F_Math_export_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ int *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (int*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = x[i];
+ *bp++ = u>>24;
+ *bp++ = u>>16;
+ *bp++ = u>>8;
+ *bp++ = u;
+ }
+}
+
+void
+Math_export_real32(void *fp)
+{
+ F_Math_export_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ bits32.x = x[i];
+ u = bits32.u;
+ *bp++ = u>>24;
+ *bp++ = u>>16;
+ *bp++ = u>>8;
+ *bp++ = u;
+ }
+}
+
+void
+Math_export_real(void *fp)
+{
+ F_Math_export_int *f;
+ int i, n;
+ uvlong u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=8*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ bits64.x = x[i];
+ u = bits64.u;
+ *bp++ = u>>56;
+ *bp++ = u>>48;
+ *bp++ = u>>40;
+ *bp++ = u>>32;
+ *bp++ = u>>24;
+ *bp++ = u>>16;
+ *bp++ = u>>8;
+ *bp++ = u;
+ }
+}
+
+
+void
+Math_bits32real(void *fp)
+{
+ F_Math_bits32real *f;
+
+ f = fp;
+ bits32.u = f->b;
+ *f->ret = bits32.x;
+}
+
+void
+Math_bits64real(void *fp)
+{
+ F_Math_bits64real *f;
+
+ f = fp;
+ bits64.u = f->b;
+ *f->ret = bits64.x;
+}
+
+void
+Math_realbits32(void *fp)
+{
+ F_Math_realbits32 *f;
+
+ f = fp;
+ bits32.x = f->x;
+ *f->ret = bits32.u;
+}
+
+void
+Math_realbits64(void *fp)
+{
+ F_Math_realbits64 *f;
+
+ f = fp;
+ bits64.x = f->x;
+ *f->ret = bits64.u;
+}
+
+
+void
+Math_getFPcontrol(void *fp)
+{
+ F_Math_getFPcontrol *f;
+
+ f = fp;
+
+ *f->ret = getFPcontrol();
+}
+
+void
+Math_getFPstatus(void *fp)
+{
+ F_Math_getFPstatus *f;
+
+ f = fp;
+
+ *f->ret = getFPstatus();
+}
+
+void
+Math_finite(void *fp)
+{
+ F_Math_finite *f;
+
+ f = fp;
+
+ *f->ret = finite(f->x);
+}
+
+void
+Math_ilogb(void *fp)
+{
+ F_Math_ilogb *f;
+
+ f = fp;
+
+ *f->ret = ilogb(f->x);
+}
+
+void
+Math_isnan(void *fp)
+{
+ F_Math_isnan *f;
+
+ f = fp;
+
+ *f->ret = isnan(f->x);
+}
+
+void
+Math_acos(void *fp)
+{
+ F_Math_acos *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_acos(f->x);
+}
+
+void
+Math_acosh(void *fp)
+{
+ F_Math_acosh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_acosh(f->x);
+}
+
+void
+Math_asin(void *fp)
+{
+ F_Math_asin *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_asin(f->x);
+}
+
+void
+Math_asinh(void *fp)
+{
+ F_Math_asinh *f;
+
+ f = fp;
+
+ *f->ret = asinh(f->x);
+}
+
+void
+Math_atan(void *fp)
+{
+ F_Math_atan *f;
+
+ f = fp;
+
+ *f->ret = atan(f->x);
+}
+
+void
+Math_atanh(void *fp)
+{
+ F_Math_atanh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_atanh(f->x);
+}
+
+void
+Math_cbrt(void *fp)
+{
+ F_Math_cbrt *f;
+
+ f = fp;
+
+ *f->ret = cbrt(f->x);
+}
+
+void
+Math_ceil(void *fp)
+{
+ F_Math_ceil *f;
+
+ f = fp;
+
+ *f->ret = ceil(f->x);
+}
+
+void
+Math_cos(void *fp)
+{
+ F_Math_cos *f;
+
+ f = fp;
+
+ *f->ret = cos(f->x);
+}
+
+void
+Math_cosh(void *fp)
+{
+ F_Math_cosh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_cosh(f->x);
+}
+
+void
+Math_erf(void *fp)
+{
+ F_Math_erf *f;
+
+ f = fp;
+
+ *f->ret = erf(f->x);
+}
+
+void
+Math_erfc(void *fp)
+{
+ F_Math_erfc *f;
+
+ f = fp;
+
+ *f->ret = erfc(f->x);
+}
+
+void
+Math_exp(void *fp)
+{
+ F_Math_exp *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_exp(f->x);
+}
+
+void
+Math_expm1(void *fp)
+{
+ F_Math_expm1 *f;
+
+ f = fp;
+
+ *f->ret = expm1(f->x);
+}
+
+void
+Math_fabs(void *fp)
+{
+ F_Math_fabs *f;
+
+ f = fp;
+
+ *f->ret = fabs(f->x);
+}
+
+void
+Math_floor(void *fp)
+{
+ F_Math_floor *f;
+
+ f = fp;
+
+ *f->ret = floor(f->x);
+}
+
+void
+Math_j0(void *fp)
+{
+ F_Math_j0 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_j0(f->x);
+}
+
+void
+Math_j1(void *fp)
+{
+ F_Math_j1 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_j1(f->x);
+}
+
+void
+Math_log(void *fp)
+{
+ F_Math_log *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_log(f->x);
+}
+
+void
+Math_log10(void *fp)
+{
+ F_Math_log10 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_log10(f->x);
+}
+
+void
+Math_log1p(void *fp)
+{
+ F_Math_log1p *f;
+
+ f = fp;
+
+ *f->ret = log1p(f->x);
+}
+
+void
+Math_rint(void *fp)
+{
+ F_Math_rint *f;
+
+ f = fp;
+
+ *f->ret = rint(f->x);
+}
+
+void
+Math_sin(void *fp)
+{
+ F_Math_sin *f;
+
+ f = fp;
+
+ *f->ret = sin(f->x);
+}
+
+void
+Math_sinh(void *fp)
+{
+ F_Math_sinh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_sinh(f->x);
+}
+
+void
+Math_sqrt(void *fp)
+{
+ F_Math_sqrt *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_sqrt(f->x);
+}
+
+void
+Math_tan(void *fp)
+{
+ F_Math_tan *f;
+
+ f = fp;
+
+ *f->ret = tan(f->x);
+}
+
+void
+Math_tanh(void *fp)
+{
+ F_Math_tanh *f;
+
+ f = fp;
+
+ *f->ret = tanh(f->x);
+}
+
+void
+Math_y0(void *fp)
+{
+ F_Math_y0 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_y0(f->x);
+}
+
+void
+Math_y1(void *fp)
+{
+ F_Math_y1 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_y1(f->x);
+}
+
+void
+Math_fdim(void *fp)
+{
+ F_Math_fdim *f;
+
+ f = fp;
+
+ *f->ret = fdim(f->x, f->y);
+}
+
+void
+Math_fmax(void *fp)
+{
+ F_Math_fmax *f;
+
+ f = fp;
+
+ *f->ret = fmax(f->x, f->y);
+}
+
+void
+Math_fmin(void *fp)
+{
+ F_Math_fmin *f;
+
+ f = fp;
+
+ *f->ret = fmin(f->x, f->y);
+}
+
+void
+Math_fmod(void *fp)
+{
+ F_Math_fmod *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_fmod(f->x, f->y);
+}
+
+void
+Math_hypot(void *fp)
+{
+ F_Math_hypot *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_hypot(f->x, f->y);
+}
+
+void
+Math_nextafter(void *fp)
+{
+ F_Math_nextafter *f;
+
+ f = fp;
+
+ *f->ret = nextafter(f->x, f->y);
+}
+
+void
+Math_pow(void *fp)
+{
+ F_Math_pow *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_pow(f->x, f->y);
+}
+
+
+
+void
+Math_FPcontrol(void *fp)
+{
+ F_Math_FPcontrol *f;
+
+ f = fp;
+
+ *f->ret = FPcontrol(f->r, f->mask);
+}
+
+void
+Math_FPstatus(void *fp)
+{
+ F_Math_FPstatus *f;
+
+ f = fp;
+
+ *f->ret = FPstatus(f->r, f->mask);
+}
+
+void
+Math_atan2(void *fp)
+{
+ F_Math_atan2 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_atan2(f->y, f->x);
+}
+
+void
+Math_copysign(void *fp)
+{
+ F_Math_copysign *f;
+
+ f = fp;
+
+ *f->ret = copysign(f->x, f->s);
+}
+
+void
+Math_jn(void *fp)
+{
+ F_Math_jn *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_jn(f->n, f->x);
+}
+
+void
+Math_lgamma(void *fp)
+{
+ F_Math_lgamma *f;
+
+ f = fp;
+
+ f->ret->t1 = __ieee754_lgamma_r(f->x, &f->ret->t0);
+}
+
+void
+Math_modf(void *fp)
+{
+ F_Math_modf *f;
+ double ipart;
+
+ f = fp;
+
+ f->ret->t1 = modf(f->x, &ipart);
+ f->ret->t0 = ipart;
+}
+
+void
+Math_pow10(void *fp)
+{
+ F_Math_pow10 *f;
+
+ f = fp;
+
+ *f->ret = ipow10(f->p);
+}
+
+void
+Math_remainder(void *fp)
+{
+ F_Math_remainder *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_remainder(f->x, f->p);
+}
+
+void
+Math_scalbn(void *fp)
+{
+ F_Math_scalbn *f;
+
+ f = fp;
+
+ *f->ret = scalbn(f->x, f->n);
+}
+
+void
+Math_yn(void *fp)
+{
+ F_Math_yn *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_yn(f->n, f->x);
+}
+
+
+/**** sorting real vectors through permutation vector ****/
+/* qsort from coma:/usr/jlb/qsort/qsort.dir/qsort.c on 28 Sep '92
+ char* has been changed to uchar*, static internal functions.
+ specialized to swapping ints (which are 32-bit anyway in limbo).
+ converted uchar* to int* (and substituted 1 for es).
+*/
+
+static int
+cmp(int *u, int *v, double *x)
+{
+ return ((x[*u]==x[*v])? 0 : ((x[*u]<x[*v])? -1 : 1));
+}
+
+#define swap(u, v) {int t = *(u); *(u) = *(v); *(v) = t;}
+
+#define vecswap(u, v, n) if(n>0){ \
+ int i = n; \
+ register int *pi = u; \
+ register int *pj = v; \
+ do { \
+ register int t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define minimum(x, y) ((x)<=(y) ? (x) : (y))
+
+static int *
+med3(int *a, int *b, int *c, double *x)
+{ return cmp(a, b, x) < 0 ?
+ (cmp(b, c, x) < 0 ? b : (cmp(a, c, x) < 0 ? c : a ) )
+ : (cmp(b, c, x) > 0 ? b : (cmp(a, c, x) < 0 ? a : c ) );
+}
+
+void
+rqsort(int *a, int n, double *x)
+{
+ int *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r;
+
+ if (n < 7) { /* Insertion sort on small arrays */
+ for (pm = a + 1; pm < a + n; pm++)
+ for (pl = pm; pl > a && cmp(pl-1, pl, x) > 0; pl--)
+ swap(pl, pl-1);
+ return;
+ }
+ pm = a + (n/2);
+ if (n > 7) {
+ pl = a;
+ pn = a + (n-1);
+ if (n > 40) { /* On big arrays, pseudomedian of 9 */
+ d = (n/8);
+ pl = med3(pl, pl+d, pl+2*d, x);
+ pm = med3(pm-d, pm, pm+d, x);
+ pn = med3(pn-2*d, pn-d, pn, x);
+ }
+ pm = med3(pl, pm, pn, x); /* On mid arrays, med of 3 */
+ }
+ swap(a, pm); /* On tiny arrays, partition around middle */
+ pa = pb = a + 1;
+ pc = pd = a + (n-1);
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a, x)) <= 0) {
+ if (r == 0) { swap(pa, pb); pa++; }
+ pb++;
+ }
+ while (pb <= pc && (r = cmp(pc, a, x)) >= 0) {
+ if (r == 0) { swap(pc, pd); pd--; }
+ pc--;
+ }
+ if (pb > pc) break;
+ swap(pb, pc);
+ pb++;
+ pc--;
+ }
+ pn = a + n;
+ r = minimum(pa-a, pb-pa); vecswap(a, pb-r, r);
+ r = minimum(pd-pc, pn-pd-1); vecswap(pb, pn-r, r);
+ if ((r = pb-pa) > 1) rqsort(a, r, x);
+ if ((r = pd-pc) > 1) rqsort(pn-r, r, x);
+}
+
+void
+Math_sort(void*fp)
+{
+ F_Math_sort *f;
+ int i, pilen, xlen, *p;
+
+ f = fp;
+
+ /* check that permutation contents are in [0,n-1] !!! */
+ p = (int*) (f->pi->data);
+ pilen = f->pi->len;
+ xlen = f->x->len - 1;
+
+ for(i = 0; i < pilen; i++) {
+ if((*p < 0) || (xlen < *p))
+ error(exMathia);
+ p++;
+ }
+
+ rqsort( (int*)(f->pi->data), f->pi->len, (double*)(f->x->data));
+}
+
+
+/************ BLAS ***************/
+
+void
+Math_dot(void *fp)
+{
+ F_Math_dot *f;
+
+ f = fp;
+ if(f->x->len!=f->y->len)
+ error(exMathia); /* incompatible lengths */
+ *f->ret = dot(f->x->len, (double*)(f->x->data), (double*)(f->y->data));
+}
+
+void
+Math_iamax(void *fp)
+{
+ F_Math_iamax *f;
+
+ f = fp;
+
+ *f->ret = iamax(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_norm2(void *fp)
+{
+ F_Math_norm2 *f;
+
+ f = fp;
+
+ *f->ret = norm2(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_norm1(void *fp)
+{
+ F_Math_norm1 *f;
+
+ f = fp;
+
+ *f->ret = norm1(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_gemm(void *fp)
+{
+ F_Math_gemm *f = fp;
+ int nrowa, ncola, nrowb, ncolb, mn, ld, m, n;
+ double *adata = 0, *bdata = 0, *cdata;
+ int nota = f->transa=='N';
+ int notb = f->transb=='N';
+ if(nota){
+ nrowa = f->m;
+ ncola = f->k;
+ }else{
+ nrowa = f->k;
+ ncola = f->m;
+ }
+ if(notb){
+ nrowb = f->k;
+ ncolb = f->n;
+ }else{
+ nrowb = f->n;
+ ncolb = f->k;
+ }
+ if( (!nota && f->transa!='C' && f->transa!='T') ||
+ (!notb && f->transb!='C' && f->transb!='T') ||
+ (f->m < 0 || f->n < 0 || f->k < 0) ){
+ error(exMathia);
+ }
+ if(f->a != H){
+ mn = f->a->len;
+ adata = (double*)(f->a->data);
+ ld = f->lda;
+ if(ld<nrowa || ld*(ncola-1)>mn)
+ error(exBounds);
+ }
+ if(f->b != H){
+ mn = f->b->len;
+ ld = f->ldb;
+ bdata = (double*)(f->b->data);
+ if(ld<nrowb || ld*(ncolb-1)>mn)
+ error(exBounds);
+ }
+ m = f->m;
+ n = f->n;
+ mn = f->c->len;
+ cdata = (double*)(f->c->data);
+ ld = f->ldc;
+ if(ld<m || ld*(n-1)>mn)
+ error(exBounds);
+
+ gemm(f->transa, f->transb, f->m, f->n, f->k, f->alpha,
+ adata, f->lda, bdata, f->ldb, f->beta, cdata, f->ldc);
+}
diff --git a/libinterp/mathmod.h b/libinterp/mathmod.h
new file mode 100644
index 00000000..f15583fc
--- /dev/null
+++ b/libinterp/mathmod.h
@@ -0,0 +1,73 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Mathmodtab[]={
+ "FPcontrol",0x6584767b,Math_FPcontrol,40,0,{0},
+ "FPstatus",0x6584767b,Math_FPstatus,40,0,{0},
+ "acos",0xa1d1fe48,Math_acos,40,0,{0},
+ "acosh",0xa1d1fe48,Math_acosh,40,0,{0},
+ "asin",0xa1d1fe48,Math_asin,40,0,{0},
+ "asinh",0xa1d1fe48,Math_asinh,40,0,{0},
+ "atan",0xa1d1fe48,Math_atan,40,0,{0},
+ "atan2",0xf293f6cf,Math_atan2,48,0,{0},
+ "atanh",0xa1d1fe48,Math_atanh,40,0,{0},
+ "bits32real",0x40a58596,Math_bits32real,40,0,{0},
+ "bits64real",0x5463c72c,Math_bits64real,40,0,{0},
+ "cbrt",0xa1d1fe48,Math_cbrt,40,0,{0},
+ "ceil",0xa1d1fe48,Math_ceil,40,0,{0},
+ "copysign",0xf293f6cf,Math_copysign,48,0,{0},
+ "cos",0xa1d1fe48,Math_cos,40,0,{0},
+ "cosh",0xa1d1fe48,Math_cosh,40,0,{0},
+ "dot",0xfeca4db6,Math_dot,40,2,{0x0,0xc0,},
+ "erf",0xa1d1fe48,Math_erf,40,0,{0},
+ "erfc",0xa1d1fe48,Math_erfc,40,0,{0},
+ "exp",0xa1d1fe48,Math_exp,40,0,{0},
+ "expm1",0xa1d1fe48,Math_expm1,40,0,{0},
+ "export_int",0x3f1d94ee,Math_export_int,40,2,{0x0,0xc0,},
+ "export_real",0xd1fb0c8c,Math_export_real,40,2,{0x0,0xc0,},
+ "export_real32",0xd1fb0c8c,Math_export_real32,40,2,{0x0,0xc0,},
+ "fabs",0xa1d1fe48,Math_fabs,40,0,{0},
+ "fdim",0xf293f6cf,Math_fdim,48,0,{0},
+ "finite",0x7b2e5f52,Math_finite,40,0,{0},
+ "floor",0xa1d1fe48,Math_floor,40,0,{0},
+ "fmax",0xf293f6cf,Math_fmax,48,0,{0},
+ "fmin",0xf293f6cf,Math_fmin,48,0,{0},
+ "fmod",0xf293f6cf,Math_fmod,48,0,{0},
+ "gemm",0x53b8cd34,Math_gemm,96,3,{0x0,0x0,0xa2,},
+ "getFPcontrol",0x616977e8,Math_getFPcontrol,32,0,{0},
+ "getFPstatus",0x616977e8,Math_getFPstatus,32,0,{0},
+ "hypot",0xf293f6cf,Math_hypot,48,0,{0},
+ "iamax",0xa5fc2e4d,Math_iamax,40,2,{0x0,0x80,},
+ "ilogb",0x7b2e5f52,Math_ilogb,40,0,{0},
+ "import_int",0x3f1d94ee,Math_import_int,40,2,{0x0,0xc0,},
+ "import_real",0xd1fb0c8c,Math_import_real,40,2,{0x0,0xc0,},
+ "import_real32",0xd1fb0c8c,Math_import_real32,40,2,{0x0,0xc0,},
+ "isnan",0x7b2e5f52,Math_isnan,40,0,{0},
+ "j0",0xa1d1fe48,Math_j0,40,0,{0},
+ "j1",0xa1d1fe48,Math_j1,40,0,{0},
+ "jn",0xb61ffc5b,Math_jn,48,0,{0},
+ "lgamma",0x6e97c646,Math_lgamma,40,0,{0},
+ "log",0xa1d1fe48,Math_log,40,0,{0},
+ "log10",0xa1d1fe48,Math_log10,40,0,{0},
+ "log1p",0xa1d1fe48,Math_log1p,40,0,{0},
+ "modf",0x6e97c646,Math_modf,40,0,{0},
+ "nextafter",0xf293f6cf,Math_nextafter,48,0,{0},
+ "norm1",0x1629207e,Math_norm1,40,2,{0x0,0x80,},
+ "norm2",0x1629207e,Math_norm2,40,2,{0x0,0x80,},
+ "pow",0xf293f6cf,Math_pow,48,0,{0},
+ "pow10",0x40a58596,Math_pow10,40,0,{0},
+ "realbits32",0x7b2e5f52,Math_realbits32,40,0,{0},
+ "realbits64",0x9589d476,Math_realbits64,40,0,{0},
+ "remainder",0xf293f6cf,Math_remainder,48,0,{0},
+ "rint",0xa1d1fe48,Math_rint,40,0,{0},
+ "scalbn",0x64fa84ba,Math_scalbn,48,0,{0},
+ "sin",0xa1d1fe48,Math_sin,40,0,{0},
+ "sinh",0xa1d1fe48,Math_sinh,40,0,{0},
+ "sort",0xfc7c7b8,Math_sort,40,2,{0x0,0xc0,},
+ "sqrt",0xa1d1fe48,Math_sqrt,40,0,{0},
+ "tan",0xa1d1fe48,Math_tan,40,0,{0},
+ "tanh",0xa1d1fe48,Math_tanh,40,0,{0},
+ "y0",0xa1d1fe48,Math_y0,40,0,{0},
+ "y1",0xa1d1fe48,Math_y1,40,0,{0},
+ "yn",0xb61ffc5b,Math_yn,48,0,{0},
+ 0
+};
+#define Mathmodlen 68
diff --git a/libinterp/mkfile b/libinterp/mkfile
new file mode 100644
index 00000000..50d86f5d
--- /dev/null
+++ b/libinterp/mkfile
@@ -0,0 +1,120 @@
+<../mkconfig
+
+LIB=libinterp.a
+
+OFILES=\
+ alt.$O\
+ comp-$OBJTYPE.$O\
+ conv.$O\
+ dec.$O\
+ dlm-$TARGMODEL.$O\
+ draw.$O\
+ freetype.$O\
+ gc.$O\
+ geom.$O\
+ heap.$O\
+ heapaudit.$O\
+ ipint.$O\
+ link.$O\
+ load.$O\
+ loader.$O\
+ math.$O\
+# prefab.$O\
+ raise.$O\
+ readmod.$O\
+ runt.$O\
+ sign.$O\
+ stack.$O\
+ tk.$O\
+ validstk.$O\
+ xec.$O\
+ das-$OBJTYPE.$O\
+ keyring.$O\
+ string.$O\
+
+HFILES=\
+ $ROOT/include/interp.h\
+ $ROOT/include/isa.h\
+ runt.h\
+ tab.h\
+
+MODULES=\
+ ../module/runt.m\
+ ../module/sys.m\
+ ../module/draw.m\
+ ../module/prefab.m\
+ ../module/math.m\
+ ../module/tk.m\
+ ../module/keyring.m\
+ ../module/loader.m\
+ ../module/freetype.m\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+runt.h:D: $MODULES
+ rm -f $target && limbo -a -I../module ../module/runt.m > $target
+
+sysmod.h:D: $MODULES
+ rm -f $target && limbo -t Sys -I../module ../module/runt.m > $target
+
+keyring.h:D: $MODULES
+ rm -f $target && limbo -t Keyring -I../module ../module/runt.m > $target
+
+drawmod.h:D: $MODULES
+ rm -f $target && limbo -t Draw -I../module ../module/runt.m > $target
+
+prefabmod.h:D: $MODULES
+ rm -f $target && limbo -t Prefab -I../module ../module/runt.m > $target
+
+tkmod.h:D: $MODULES
+ rm -f $target && limbo -t Tk -I../module ../module/runt.m > $target
+
+mathmod.h:D: $MODULES
+ rm -f $target && limbo -t Math -I../module ../module/runt.m > $target
+
+loadermod.h:D: $MODULES
+ rm -f $target && limbo -t Loader -I../module ../module/runt.m > $target
+
+freetypemod.h:D: $MODULES
+ rm -f $target && limbo -t Freetype -I../module ../module/runt.m > $target
+
+benchmod.h:D: ../module/bench.m
+ rm -f $target && limbo -t Bench -I../module ../module/bench.m > $target
+
+bench.h:D:../module/bench.m
+ rm -f $target && limbo -a -I../module ../module/bench.m > $target
+
+xec.$O: optab.h $ROOT/include/pool.h
+tk.$O: $ROOT/include/tk.h $ROOT/include/pool.h
+draw.$O: $ROOT/include/draw.h $ROOT/include/drawif.h
+prefab.$O: $ROOT/include/draw.h\
+ $ROOT/include/prefab.h
+
+runt.$O: sysmod.h
+prefab.$O: prefabmod.h
+draw.$O: drawmod.h
+tk.$O: $ROOT/include/draw.h tkmod.h
+math.$O: mathmod.h
+keyring.$O: keyring.h $ROOT/libkeyring/keys.h
+ipint.$O: keyring.h
+loader.$O: loadermod.h
+freetype.$O: freetypemod.h $ROOT/include/freetype.h
+math.$O: $ROOT/include/mathi.h
+
+das-spim.c:N: das-mips.c
+das-68000.c:N: das-68020.c
+comp-spim.c:N: comp-mips.c
+
+kif.c: kif.h
+ rm -f $target && kif -t $SYSTARG kif.h > $target
+kif.$O: kif.c
+ $CC $CFLAGS kif.c && rm -f kif.c
+
+# optab.h: $ROOT/include/isa.h mkoptab
+# $SHELLNAME mkoptab > $target
+
+# Do not remove optab.h, because the script that builds
+# it works only on UNIX and Plan 9.
+
+nuke:EV: nuke-std
+ rm -f runt.h sysmod.h drawmod.h prefabmod.h tkmod.h mathmod.h keyring.h readimagemod.h loadermod.h freetypemod.h kif.c
diff --git a/libinterp/mkoptab b/libinterp/mkoptab
new file mode 100644
index 00000000..9b38b663
--- /dev/null
+++ b/libinterp/mkoptab
@@ -0,0 +1,19 @@
+rm -f optab.h
+tr '[A-Z]' '[a-z]' <../include/isa.h >optab.h
+ed optab.h <<'HERE'
+1;/enum/c
+void (*optab[256])(void) =
+.
+/}/+1,$ d
+,s/^[ ]*i/ /g
+1;/nop/s//badop/
+1;/exit/s//i&/
+1;/goto/s//i&/
+1;/case/s//i&/
+1;/load/s//i&/
+1;/recv/s//i&/
+1;/send/s//i&/
+1;/raise/s//i&/
+w
+q
+HERE
diff --git a/libinterp/optab.h b/libinterp/optab.h
new file mode 100644
index 00000000..e9a824f1
--- /dev/null
+++ b/libinterp/optab.h
@@ -0,0 +1,179 @@
+void (*optab[256])(void) =
+{
+ badop,
+ alt,
+ nbalt,
+ igoto,
+ call,
+ frame,
+ spawn,
+ runt,
+ iload,
+ mcall,
+ mspawn,
+ mframe,
+ ret,
+ jmp,
+ icase,
+ iexit,
+ new,
+ newa,
+ newcb,
+ newcw,
+ newcf,
+ newcp,
+ newcm,
+ newcmp,
+ isend,
+ irecv,
+ consb,
+ consw,
+ consp,
+ consf,
+ consm,
+ consmp,
+ headb,
+ headw,
+ headp,
+ headf,
+ headm,
+ headmp,
+ tail,
+ lea,
+ indx,
+ movp,
+ movm,
+ movmp,
+ movb,
+ movw,
+ movf,
+ cvtbw,
+ cvtwb,
+ cvtfw,
+ cvtwf,
+ cvtca,
+ cvtac,
+ cvtwc,
+ cvtcw,
+ cvtfc,
+ cvtcf,
+ addb,
+ addw,
+ addf,
+ subb,
+ subw,
+ subf,
+ mulb,
+ mulw,
+ mulf,
+ divb,
+ divw,
+ divf,
+ modw,
+ modb,
+ andb,
+ andw,
+ orb,
+ orw,
+ xorb,
+ xorw,
+ shlb,
+ shlw,
+ shrb,
+ shrw,
+ insc,
+ indc,
+ addc,
+ lenc,
+ lena,
+ lenl,
+ beqb,
+ bneb,
+ bltb,
+ bleb,
+ bgtb,
+ bgeb,
+ beqw,
+ bnew,
+ bltw,
+ blew,
+ bgtw,
+ bgew,
+ beqf,
+ bnef,
+ bltf,
+ blef,
+ bgtf,
+ bgef,
+ beqc,
+ bnec,
+ bltc,
+ blec,
+ bgtc,
+ bgec,
+ slicea,
+ slicela,
+ slicec,
+ indw,
+ indf,
+ indb,
+ negf,
+ movl,
+ addl,
+ subl,
+ divl,
+ modl,
+ mull,
+ andl,
+ orl,
+ xorl,
+ shll,
+ shrl,
+ bnel,
+ bltl,
+ blel,
+ bgtl,
+ bgel,
+ beql,
+ cvtlf,
+ cvtfl,
+ cvtlw,
+ cvtwl,
+ cvtlc,
+ cvtcl,
+ headl,
+ consl,
+ newcl,
+ casec,
+ indl,
+ movpc,
+ tcmp,
+ mnewz,
+ cvtrf,
+ cvtfr,
+ cvtws,
+ cvtsw,
+ lsrw,
+ lsrl,
+ eclr, /* unused */
+ newz,
+ newaz,
+ iraise,
+ casel,
+ mulx,
+ divx,
+ cvtxx,
+ mulx0,
+ divx0,
+ cvtxx0,
+ mulx1,
+ divx1,
+ cvtxx1,
+ cvtfx,
+ cvtxf,
+ iexpw,
+ iexpl,
+ iexpf,
+ self,
+ /* fix maxdis if you add opcodes */
+};
diff --git a/libinterp/prefab.c b/libinterp/prefab.c
new file mode 100644
index 00000000..086bedd4
--- /dev/null
+++ b/libinterp/prefab.c
@@ -0,0 +1,824 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "prefabmod.h"
+#include "draw.h"
+#include "drawif.h"
+#include "prefab.h"
+#include "raise.h"
+
+uchar elementmap[] = Prefab_Element_map;
+uchar compoundmap[] = Prefab_Compound_map;
+uchar layoutmap[] = Prefab_Layout_map;
+
+void freeprefabcompound(Heap*, int);
+
+Type* TCompound;
+Type* TElement;
+Type* TLayout;
+
+/* Infrared remote buttons known to Compound_select */
+enum
+{
+ IRFF = 14,
+ IRRew = 15,
+ IRUp = 16,
+ IRDn = 17,
+ IRSelect = 18,
+ IREnter = 20,
+};
+
+void
+prefabmodinit(void)
+{
+ TElement = dtype(freeheap, sizeof(PElement), elementmap, sizeof(elementmap));
+ TLayout = dtype(freeheap, Prefab_Layout_size, layoutmap, sizeof(layoutmap));
+ TCompound = dtype(freeprefabcompound, sizeof(PCompound), compoundmap, sizeof(compoundmap));
+ builtinmod("$Prefab", Prefabmodtab, Prefabmodlen);
+}
+
+PElement*
+checkelement(Prefab_Element *de)
+{
+ PElement *pe;
+
+ pe = lookupelement(de);
+ if(pe == H)
+ error(exType);
+ return pe;
+}
+
+PCompound*
+checkcompound(Prefab_Compound *de)
+{
+ PCompound *pe;
+
+ pe = lookupcompound(de);
+ if(pe == H)
+ error(exType);
+ return pe;
+}
+
+PElement*
+lookupelement(Prefab_Element *de)
+{
+ PElement *pe;
+ if(de == H)
+ return H;
+ if(D2H(de)->t != TElement)
+ return H;
+ pe = (PElement*)de;
+ if(de->kind!=pe->pkind || de->kids!=pe->first)
+ return H;
+ return pe;
+}
+
+PCompound*
+lookupcompound(Prefab_Compound *dc)
+{
+ if(dc == H)
+ return H;
+ if(D2H(dc)->t != TCompound)
+ return H;
+ return (PCompound*)dc;
+}
+
+void
+freeprefabcompound(Heap *h, int swept)
+{
+ Image *i;
+ Prefab_Compound *d;
+ PCompound *pc;
+
+ d = H2D(Prefab_Compound*, h);
+ pc = lookupcompound(d);
+ /* disconnect compound from image refresh daemon */
+ i = lookupimage(pc->c.image);
+ if(i != nil)
+ delrefresh(i);
+ if(!swept && TCompound->np)
+ freeptrs(d, TCompound);
+ /* header will be freed by caller */
+}
+
+static
+PElement*
+findtag(PElement *pelem, char *tag)
+{
+ PElement *pe, *t;
+ List *l;
+
+ if(pelem==H || tag[0]==0)
+ return pelem;
+ for(l=pelem->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ if(strcmp(tag, string2c(pe->e.tag)) == 0)
+ return pe;
+ else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
+ t = findtag(pe, tag);
+ if(t != H)
+ return t;
+ }
+ }
+ return H;
+}
+
+int
+badenviron(Prefab_Environ *env, int err)
+{
+ Prefab_Style *s;
+
+ if(env == H)
+ goto bad;
+ s = env->style;
+ if(s == H)
+ goto bad;
+ if(s->titlefont==H || s->textfont==H)
+ goto bad;
+ if(s->elemcolor==H || s->edgecolor==H)
+ goto bad;
+ if(s->titlecolor==H || s->textcolor==H || s->highlightcolor==H)
+ goto bad;
+ return 0;
+bad:
+ if(err)
+ error(exType);
+ return 1;
+}
+
+void
+Element_iconseparator(void *fp, int kind)
+{
+ F_Element_icon *f;
+ PElement *e;
+ Image *icon;
+ int locked;
+
+ f = fp;
+ badenviron(f->env, 1);
+ checkimage(f->mask);
+ icon = checkimage(f->icon);
+ locked = lockdisplay(icon->display);
+ destroy(*f->ret);
+ *f->ret = H;
+ if(kind == ESeparator)
+ e = separatorelement(f->env, f->r, f->icon, f->mask);
+ else
+ e = iconelement(f->env, f->r, f->icon, f->mask);
+ *f->ret = (Prefab_Element*)e;
+ if(locked)
+ unlockdisplay(icon->display);
+}
+
+void
+Element_icon(void *fp)
+{
+ Element_iconseparator(fp, EIcon);
+}
+
+void
+Element_separator(void *fp)
+{
+ Element_iconseparator(fp, ESeparator);
+}
+
+void
+Element_text(void *fp)
+{
+ F_Element_text *f;
+ PElement *pelem;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ badenviron(f->env, 1);
+ if(f->kind!=EText && f->kind!=ETitle)
+ return;
+
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pelem = textelement(f->env, f->text, f->r, f->kind);
+ *f->ret = (Prefab_Element*)pelem;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_layout(void *fp)
+{
+ F_Element_layout *f;
+ PElement *pelem;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ badenviron(f->env, 1);
+ if(f->kind!=EText && f->kind!=ETitle)
+ return;
+
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pelem = layoutelement(f->env, f->lay, f->r, f->kind);
+ *f->ret = (Prefab_Element*)pelem;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_elist(void *fp)
+{
+ F_Element_elist *f;
+ PElement *pelist;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ if(f->elem != H)
+ checkelement(f->elem);
+ badenviron(f->env, 1);
+ if(f->kind!=EHorizontal && f->kind!=EVertical)
+ return;
+
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pelist = elistelement(f->env, f->elem, f->kind);
+ *f->ret = (Prefab_Element*)pelist;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_append(void *fp)
+{
+ F_Element_append *f;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->elist==H || f->elem==H)
+ return;
+
+ badenviron(f->elist->environ, 1);
+ checkelement(f->elist);
+ checkelement(f->elem);
+
+ if(f->elist->kind!=EHorizontal && f->elist->kind!=EVertical)
+ return;
+
+ if(appendelist(f->elist, f->elem) != H)
+ *f->ret = 1;
+}
+
+void
+Element_adjust(void *fp)
+{
+ F_Element_adjust *f;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ checkelement(f->elem);
+ badenviron(f->elem->environ, 1);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ adjustelement(f->elem, f->equal, f->dir);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_show(void *fp)
+{
+ F_Element_show *f;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ checkelement(f->elem);
+ checkelement(f->elist);
+ badenviron(f->elem->environ, 1);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ *f->ret = showelement(f->elist, f->elem);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_clip(void *fp)
+{
+ F_Element_clip *f;
+ Rectangle r;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ checkelement(f->elem);
+ badenviron(f->elem->environ, 1);
+ R2R(r, f->r);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ clipelement(f->elem, r);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_translatescroll(void *fp, int trans)
+{
+ F_Element_scroll *f;
+ Point d;
+ Display *disp;
+ int locked, moved;
+
+ f = fp;
+ checkelement(f->elem);
+ badenviron(f->elem->environ, 1);
+ P2P(d, f->d);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ if(trans)
+ translateelement(f->elem, d);
+ else{
+ moved = 0;
+ scrollelement(f->elem, d, &moved);
+ }
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_scroll(void *fp)
+{
+ Element_translatescroll(fp, 0);
+}
+
+void
+Element_translate(void *fp)
+{
+ Element_translatescroll(fp, 1);
+}
+
+void
+Compound_iconbox(void *fp)
+{
+ F_Compound_iconbox *f;
+ Image *icon;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ checkimage(f->mask);
+ icon = checkimage(f->icon);
+ locked = lockdisplay(icon->display);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = iconbox(f->env, f->p, f->title, f->icon, f->mask);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(icon->display);
+}
+
+void
+Compound_textbox(void *fp)
+{
+ F_Compound_textbox *f;
+ Display *disp;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = textbox(f->env, f->r, f->title, f->text);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Compound_layoutbox(void *fp)
+{
+ F_Compound_layoutbox *f;
+ Display *disp;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = layoutbox(f->env, f->r, f->title, f->lay);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Compound_box(void *fp)
+{
+ F_Compound_box *f;
+ Display *disp;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ if(f->title != H)
+ checkelement(f->title);
+ checkelement(f->elist);
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = box(f->env, f->p, f->title, f->elist);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Compound_draw(void *fp)
+{
+ F_Compound_draw *f;
+ PCompound *pc;
+ int locked;
+
+ f = fp;
+ if(f->comp == H)
+ return;
+ pc = checkcompound(f->comp);
+ badenviron(pc->c.environ, 1);
+ locked = lockdisplay(pc->display);
+ drawcompound(&pc->c);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+void
+Compound_redraw(void *fp)
+{
+ F_Compound_redraw *f;
+ PCompound *pc;
+ Image *i;
+ int locked;
+
+ f = fp;
+ if(f->comp == H)
+ return;
+ pc = checkcompound(f->comp);
+ badenviron(pc->c.environ, 1);
+ i = checkimage(pc->c.image);
+ locked = lockdisplay(pc->display);
+ redrawcompound(i, IRECT(f->r), &pc->c);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+static
+PElement*
+pelement(Prefab_Compound *comp, Prefab_Element *elem)
+{
+ PElement *pe;
+
+ if(comp == H)
+ return H;
+ checkcompound(comp);
+ badenviron(comp->environ, 1);
+ pe = lookupelement(elem);
+ return pe;
+}
+
+void
+Compound_highlight(void *fp)
+{
+ F_Compound_highlight *f;
+ PCompound *pc;
+ PElement *pe;
+ Image *i;
+ int locked;
+
+ f = fp;
+ pe = pelement(f->comp, f->elem);
+ if(pe == H)
+ return;
+ pc = (PCompound*)f->comp;
+ i = checkimage(pc->c.image);
+ locked = lockdisplay(pc->display);
+ highlightelement(&pe->e, i, &pc->c, f->on);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+void
+Compound_scroll(void *fp)
+{
+ F_Compound_scroll *f;
+ PCompound *pc;
+ PElement *pe;
+ int locked;
+ Image *i;
+ int moved;
+
+ f = fp;
+ pe = pelement(f->comp, f->elem);
+ if(pe == H)
+ return;
+ pc = (PCompound*)f->comp;
+ i = checkimage(pc->c.image);
+ locked = lockdisplay(pc->display);
+ moved = 0;
+ scrollelement(&pe->e, IPOINT(f->d), &moved);
+ if(moved){
+ drawelement(&pe->e, i, IRECT(pe->e.r), 0, 0);
+ flushimage(pc->display, 1);
+ }
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+void
+Compound_show(void *fp)
+{
+ F_Compound_show *f;
+ PCompound *pc;
+ PElement *pe;
+ int locked;
+
+ f = fp;
+ pe = pelement(f->comp, f->elem);
+ if(pe == H)
+ return;
+ pc = (PCompound*)f->comp;
+ locked = lockdisplay(pc->display);
+ *f->ret = showelement(pc->c.contents, &pe->e);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+static
+PElement*
+element(PElement *plist, int index, int *ip)
+{
+ int i;
+ PElement *pe;
+ List *l;
+
+ i = 0;
+ pe = H;
+ for(l=plist->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ if(pe->pkind == ESeparator)
+ continue;
+ if(i == index)
+ break;
+ i++;
+ }
+ if(ip)
+ *ip = i;
+ if(l == H)
+ return H;
+ return pe;
+}
+
+static
+int
+wrapelement(PElement *plist, int index, int ntag)
+{
+ int i, wrap;
+
+ if(ntag > 0){
+ if(index < 0)
+ return ntag-1;
+ if(index >= ntag)
+ return 0;
+ return index;
+ }
+ wrap = 1;
+ if(index < 0){
+ index = 1000000; /* will seek to end */
+ wrap = 0;
+ }
+ if(element(plist, index, &i)==H && index!=0){
+ if(wrap) /* went off end; wrap to beginning */
+ return wrapelement(plist, 0, 0);
+ if(i > 0)
+ --i;
+ }
+ return i;
+}
+
+void
+dohighlight(PCompound *pc, PElement *list, PElement *pe, int on)
+{
+ Image *i;
+
+ /* see if we need to scroll */
+ i = lookupimage(pc->c.image);
+ if(i == nil)
+ return;
+ if(on && showelement(&list->e, &pe->e))
+ redrawcompound(i, IRECT(pc->c.contents->r), &pc->c);
+ highlightelement(&pe->e, i, &pc->c, on);
+}
+
+void
+highlight(PCompound *pc, PElement *list, int index, int on)
+{
+ dohighlight(pc, list, element(list, index, nil), on);
+}
+
+static
+PElement**
+tags(PElement *pelem, int *ntag)
+{
+ int n, nalloc, nn;
+ List *l;
+ PElement *pe, **tagged, **ntagged;
+
+ n = 0;
+ nalloc = 0;
+ tagged = nil;
+ *ntag = 0;
+ for(l=pelem->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ if(pe->e.tag != H){
+ if(nalloc == n){
+ nalloc += 10;
+ tagged = realloc(tagged, nalloc*sizeof(PElement*));
+ if(tagged == nil)
+ return nil;
+ }
+ tagged[n++] = pe;
+ }else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
+ ntagged = tags(pe, &nn);
+ if(nn > 0){
+ if(nalloc < n+nn){
+ nalloc = n+nn+10;
+ tagged = realloc(tagged, nalloc*sizeof(PElement*));
+ if(tagged == nil){
+ free(ntagged);
+ return nil;
+ }
+ }
+ memmove(tagged+n, ntagged, nn*sizeof(PElement*));
+ free(ntagged);
+ n += nn;
+ }
+ }
+ }
+ *ntag = n;
+ return tagged;
+}
+
+void
+doselect(void *fp, int dotags)
+{
+ F_Compound_select *f;
+ PCompound *pc;
+ PElement *pe;
+ WORD *val;
+ List *l;
+ Prefab_Element *t;
+ int i, lasti, ntag;
+ PElement **tagged;
+ int locked;
+
+ f = fp;
+ pc = checkcompound(f->comp);
+ pe = lookupelement(f->elem);
+ if(pe->pkind!=EHorizontal && pe->pkind!=EVertical || pe->nkids == 0){
+ Bad:
+ destroy(f->ret->t2);
+ f->ret->t0 = 9999;
+ f->ret->t1 = 0;
+ f->ret->t2 = H;
+ return;
+ }
+ ntag = 0;
+ tagged = 0;
+ /* check at least one selectable item */
+ if(dotags){
+ tagged = tags(pe, &ntag);
+ if(ntag > 0)
+ goto OK;
+ }else
+ for(l=pe->first; l!=H; l=l->tail){
+ t = *(Prefab_Element**)l->data;
+ if(t->kind != ESeparator)
+ goto OK;
+ }
+ goto Bad;
+
+ OK:
+ i = f->i;
+ i = wrapelement(pe, i, ntag);
+ lasti = i;
+ locked = lockdisplay(pc->display);
+ if(dotags)
+ dohighlight(pc, pe, tagged[i], 1);
+ else
+ highlight(pc, pe, i, 1);
+ /* val must be in shared memory, but stacks not shared */
+ val = malloc(sizeof(WORD));
+ if(val == nil)
+ goto Bad;
+ for(;;){
+ if(lasti != i){
+ if(dotags){
+ dohighlight(pc, pe, tagged[lasti], 0);
+ dohighlight(pc, pe, tagged[i], 1);
+ }else{
+ highlight(pc, pe, lasti, 0);
+ highlight(pc, pe, i, 1);
+ }
+ lasti = i;
+ }
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+ crecv(f->c, val);
+ locked = lockdisplay(pc->display);
+ switch(*val){
+ case IRUp:
+ if(pe->pkind != EVertical)
+ goto Default;
+ goto Up;
+ case IRRew:
+ if(pe->pkind != EHorizontal)
+ goto Default;
+ Up:
+ i = wrapelement(pe, i-1, ntag);
+ break;
+ case IRSelect:
+ if(dotags)
+ dohighlight(pc, pe, tagged[i], 0);
+ else
+ highlight(pc, pe, i, 0);
+ f->ret->t0 = *val;
+ f->ret->t1 = i;
+ Return:
+ flushimage(pc->display, 1);
+ if(dotags)
+ pe = tagged[i];
+ else
+ pe = element(pe, i, nil);
+ destroy(f->ret->t2);
+ D2H(pe)->ref++;
+ f->ret->t2 = &pe->e;
+ if(locked)
+ unlockdisplay(pc->display);
+ free(val);
+ free(tagged);
+ return;
+ case IRDn:
+ if(pe->pkind != EVertical)
+ goto Default;
+ goto Down;
+ case IRFF:
+ if(pe->pkind != EHorizontal)
+ goto Default;
+ Down:
+ i = wrapelement(pe, i+1, ntag);
+ break;
+ default:
+ Default:
+ if(dotags)
+ dohighlight(pc, pe, tagged[lasti], 0);
+ else
+ highlight(pc, pe, lasti, 0);
+ f->ret->t0 = *val;
+ f->ret->t1 = i;
+ goto Return;
+ }
+ }
+}
+
+void
+Compound_tagselect(void *fp)
+{
+ doselect(fp, 1);
+}
+
+void
+Compound_select(void *fp)
+{
+ doselect(fp, 0);
+}
diff --git a/libinterp/raise.c b/libinterp/raise.c
new file mode 100644
index 00000000..b7a9ad5d
--- /dev/null
+++ b/libinterp/raise.c
@@ -0,0 +1,25 @@
+/*
+ * Exceptions thrown by the interpreter
+ */
+char exAlt[] = "alt send/recv on same chan";
+char exBusy[] = "channel busy";
+char exModule[] = "module not loaded";
+char exCompile[] = "compile failed";
+char exCrange[] = "constant range ";
+char exCctovflw[] = "constant table overflow";
+char exCphase[] = "compiler phase error";
+char exType[] = "type not constructed correctly";
+char exZdiv[] = "zero divide";
+char exHeap[] = "out of memory: heap";
+char exImage[] = "out of memory: image";
+char exItype[] = "inconsistent type";
+char exMathia[] = "invalid math argument";
+char exBounds[] = "array bounds error";
+char exNegsize[] = "negative array size";
+char exNomem[] = "out of memory: main";
+char exSpawn[] = "spawn a builtin module";
+char exOp[] = "illegal dis instruction";
+char exTcheck[] = "type check";
+char exInval[] = "invalid argument";
+char exNilref[] = "dereference of nil";
+char exRange[] = "value out of range";
diff --git a/libinterp/readmod.c b/libinterp/readmod.c
new file mode 100644
index 00000000..eebc9ba5
--- /dev/null
+++ b/libinterp/readmod.c
@@ -0,0 +1,84 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+readmod(char *path, Module *m, int sync)
+{
+ Dir *d;
+ int fd, n, dynld;
+ uchar *code;
+ Module *ans;
+ ulong length;
+
+ if(path[0] == '$') {
+ if(m == nil)
+ kwerrstr("module not built-in");
+ return m;
+ }
+
+ ans = nil;
+ code = nil;
+ length = 0;
+ dynld = 0;
+
+ if(sync)
+ release();
+
+ d = nil;
+ fd = kopen(path, OREAD);
+ if(fd < 0)
+ goto done;
+
+ if((d = kdirfstat(fd)) == nil)
+ goto done;
+
+ if(m != nil) {
+ if(d->dev == m->dev && d->type == m->dtype &&
+ d->mtime == m->mtime &&
+ d->qid.type == m->qid.type && d->qid.path == m->qid.path && d->qid.vers == m->qid.vers) {
+ ans = m;
+ goto done;
+ }
+ }
+
+ if(d->length < 0 || d->length >= 8*1024*1024){
+ kwerrstr("implausible length");
+ goto done;
+ }
+ if((d->mode&0111) && dynldable(fd)){
+ dynld = 1;
+ goto done1;
+ }
+ length = d->length;
+ code = mallocz(length, 0);
+ if(code == nil)
+ goto done;
+
+ n = kread(fd, code, length);
+ if(n != length) {
+ free(code);
+ code = nil;
+ }
+done:
+ if(fd >= 0)
+ kclose(fd);
+done1:
+ if(sync)
+ acquire();
+ if(m != nil && ans == nil)
+ unload(m);
+ if(code != nil) {
+ ans = parsemod(path, code, length, d);
+ free(code);
+ }
+ else if(dynld){
+ kseek(fd, 0, 0);
+ ans = newdyncode(fd, path, d);
+ kclose(fd);
+ }
+ free(d);
+ return ans;
+}
diff --git a/libinterp/runt.c b/libinterp/runt.c
new file mode 100644
index 00000000..81a5490b
--- /dev/null
+++ b/libinterp/runt.c
@@ -0,0 +1,496 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "runt.h"
+#include "sysmod.h"
+#include "raise.h"
+
+
+static int utfnleng(char*, int, int*);
+
+void
+sysmodinit(void)
+{
+ sysinit();
+ builtinmod("$Sys", Sysmodtab, Sysmodlen);
+}
+
+int
+xprint(Prog *xp, void *vfp, void *vva, String *s1, char *buf, int n)
+{
+ WORD i;
+ void *p;
+ LONG bg;
+ Type *t;
+ double d;
+ String *ss;
+ ulong *ptr;
+ uchar *fp, *va;
+ int nc, c, isbig, isr, sip;
+ char *b, *eb, *f, fmt[32];
+ Rune r;
+
+ fp = vfp;
+ va = vva;
+
+ sip = 0;
+ isr = 0;
+ if(s1 == H)
+ return 0;
+ nc = s1->len;
+ if(nc < 0) {
+ nc = -nc;
+ isr = 1;
+ }
+
+ b = buf;
+ eb = buf+n-1;
+ while(nc--) {
+ c = isr ? s1->Srune[sip] : s1->Sascii[sip];
+ sip++;
+ if(c != '%') {
+ if(b < eb) {
+ if(c < Runeself)
+ *b++ = c;
+ else
+ b += snprint(b, eb-b, "%C", c);
+ }
+ continue;
+ }
+ f = fmt;
+ *f++ = c;
+ isbig = 0;
+ while(nc--) {
+ c = isr ? s1->Srune[sip] : s1->Sascii[sip];
+ sip++;
+ *f++ = c;
+ *f = '\0';
+ switch(c) {
+ default:
+ continue;
+ case '*':
+ i = *(WORD*)va;
+ f--;
+ f += snprint(f, sizeof(fmt)-(f-fmt), "%d", i);
+ va += IBY2WD;
+ continue;
+ case 'b':
+ f[-1] = 'l';
+ *f++ = 'l';
+ *f = '\0';
+ isbig = 1;
+ continue;
+ case '%':
+ if(b < eb)
+ *b++ = '%';
+ break;
+ case 'q':
+ case 's':
+ ss = *(String**)va;
+ va += IBY2WD;
+ if(ss == H)
+ p = "";
+ else
+ if(ss->len < 0) {
+ f[-1] += 'A'-'a';
+ ss->Srune[-ss->len] = L'\0';
+ p = ss->Srune;
+ }
+ else {
+ ss->Sascii[ss->len] = '\0';
+ p = ss->Sascii;
+ }
+ b += snprint(b, eb-b, fmt, p);
+ break;
+ case 'E':
+ f--;
+ r = 0x00c9; /* L'É' */
+ f += runetochar(f, &r); /* avoid clash with ether address */
+ *f = '\0';
+ /* fall through */
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'G':
+ while((va - fp) & (sizeof(REAL)-1))
+ va++;
+ d = *(REAL*)va;
+ b += snprint(b, eb-b, fmt, d);
+ va += sizeof(REAL);
+ break;
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'c':
+ if(isbig) {
+ while((va - fp) & (IBY2LG-1))
+ va++;
+ bg = *(LONG*)va;
+ b += snprint(b, eb-b, fmt, bg);
+ va += IBY2LG;
+ }
+ else {
+ i = *(WORD*)va;
+ /* always a unicode character */
+ if(c == 'c')
+ f[-1] = 'C';
+ b += snprint(b, eb-b, fmt, i);
+ va += IBY2WD;
+ }
+ break;
+ case 'r':
+ b = syserr(b, eb, xp);
+ break;
+/* Debugging formats - may disappear */
+ case 'H':
+ ptr = *(ulong**)va;
+ c = -1;
+ t = nil;
+ if(ptr != H) {
+ c = D2H(ptr)->ref;
+ t = D2H(ptr)->t;
+ }
+ b += snprint(b, eb-b, "%d.%.8lux", c, (ulong)t);
+ va += IBY2WD;
+ break;
+ }
+ break;
+ }
+ }
+ return b - buf;
+}
+
+int
+bigxprint(Prog *xp, void *vfp, void *vva, String *s1, char **buf, int s)
+{
+ char *b;
+ int m, n;
+
+ m = s;
+ for (;;) {
+ m *= 2;
+ b = malloc(m);
+ if (b == nil)
+ error(exNomem);
+ n = xprint(xp, vfp, vva, s1, b, m);
+ if (n < m-UTFmax-2)
+ break;
+ free(b);
+ }
+ *buf = b;
+ return n;
+}
+
+void
+Sys_sprint(void *fp)
+{
+ int n;
+ char buf[256], *b = buf;
+ F_Sys_sprint *f;
+
+ f = fp;
+ n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
+ if (n >= sizeof(buf)-UTFmax-2)
+ n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
+ b[n] = '\0';
+ retstr(b, f->ret);
+ if (b != buf)
+ free(b);
+}
+
+void
+Sys_aprint(void *fp)
+{
+ int n;
+ char buf[256], *b = buf;
+ F_Sys_aprint *f;
+
+ f = fp;
+ n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
+ if (n >= sizeof(buf)-UTFmax-2)
+ n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
+ destroy(*f->ret);
+ *f->ret = mem2array(b, n);
+ if (b != buf)
+ free(b);
+}
+
+static int
+tokdelim(int c, String *d)
+{
+ int l;
+ char *p;
+ Rune *r;
+
+ l = d->len;
+ if(l < 0) {
+ l = -l;
+ for(r = d->Srune; l != 0; l--)
+ if(*r++ == c)
+ return 1;
+ return 0;
+ }
+ for(p = d->Sascii; l != 0; l--)
+ if(*p++ == c)
+ return 1;
+ return 0;
+}
+
+void
+Sys_tokenize(void *fp)
+{
+ String *s, *d;
+ List **h, *l, *nl;
+ F_Sys_tokenize *f;
+ int n, c, nc, first, last, srune;
+
+ f = fp;
+ s = f->s;
+ d = f->delim;
+
+ if(s == H || d == H) {
+ f->ret->t0 = 0;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ return;
+ }
+
+ n = 0;
+ l = H;
+ h = &l;
+ first = 0;
+ srune = 0;
+
+ nc = s->len;
+ if(nc < 0) {
+ nc = -nc;
+ srune = 1;
+ }
+
+ while(first < nc) {
+ while(first < nc) {
+ c = srune ? s->Srune[first] : s->Sascii[first];
+ if(tokdelim(c, d) == 0)
+ break;
+ first++;
+ }
+
+ last = first;
+
+ while(last < nc) {
+ c = srune ? s->Srune[last] : s->Sascii[last];
+ if(tokdelim(c, d) != 0)
+ break;
+ last++;
+ }
+
+ if(first == last)
+ break;
+
+ nl = cons(IBY2WD, h);
+ nl->tail = H;
+ nl->t = &Tptr;
+ Tptr.ref++;
+ *(String**)nl->data = slicer(first, last, s);
+ h = &nl->tail;
+
+ first = last;
+ n++;
+ }
+
+ f->ret->t0 = n;
+ destroy(f->ret->t1);
+ f->ret->t1 = l;
+}
+
+void
+Sys_utfbytes(void *fp)
+{
+ Array *a;
+ int nbyte;
+ F_Sys_utfbytes *f;
+
+ f = fp;
+ a = f->buf;
+ if(a == H || (UWORD)f->n > a->len)
+ error(exBounds);
+
+ utfnleng((char*)a->data, f->n, &nbyte);
+ *f->ret = nbyte;
+}
+
+void
+Sys_byte2char(void *fp)
+{
+ Rune r;
+ char *p;
+ int n, w;
+ Array *a;
+ F_Sys_byte2char *f;
+
+ f = fp;
+ a = f->buf;
+ n = f->n;
+ if(a == H || (UWORD)n >= a->len)
+ error(exBounds);
+ r = a->data[n];
+ if(r < Runeself){
+ f->ret->t0 = r;
+ f->ret->t1 = 1;
+ f->ret->t2 = 1;
+ return;
+ }
+ p = (char*)a->data+n;
+ if(n+UTFmax <= a->len || fullrune(p, a->len-n))
+ w = chartorune(&r, p);
+ else {
+ /* insufficient data */
+ f->ret->t0 = Runeerror;
+ f->ret->t1 = 0;
+ f->ret->t2 = 0;
+ return;
+ }
+ if(r == Runeerror && w==1){ /* encoding error */
+ f->ret->t0 = Runeerror;
+ f->ret->t1 = 1;
+ f->ret->t2 = 0;
+ return;
+ }
+ f->ret->t0 = r;
+ f->ret->t1 = w;
+ f->ret->t2 = 1;
+}
+
+void
+Sys_char2byte(void *fp)
+{
+ F_Sys_char2byte *f;
+ Array *a;
+ int n, c;
+ Rune r;
+
+ f = fp;
+ a = f->buf;
+ n = f->n;
+ c = f->c;
+ if(a == H || (UWORD)n>=a->len)
+ error(exBounds);
+ if(c<0 || c>=(1<<16))
+ c = Runeerror;
+ if(c < Runeself){
+ a->data[n] = c;
+ *f->ret = 1;
+ return;
+ }
+ r = c;
+ if(n+UTFmax<=a->len || runelen(c)<=a->len-n){
+ *f->ret = runetochar((char*)a->data+n, &r);
+ return;
+ }
+ *f->ret = 0;
+}
+
+Module *
+builtinmod(char *name, void *vr, int rlen)
+{
+ Runtab *r = vr;
+ Type *t;
+ Module *m;
+ Link *l;
+
+ m = newmod(name);
+ if(rlen == 0){
+ while(r->name){
+ rlen++;
+ r++;
+ }
+ r = vr;
+ }
+ l = m->ext = (Link*)malloc((rlen+1)*sizeof(Link));
+ if(l == nil){
+ freemod(m);
+ return nil;
+ }
+ while(r->name) {
+ t = dtype(freeheap, r->size, r->map, r->np);
+ runtime(m, l, r->name, r->sig, r->fn, t);
+ r++;
+ l++;
+ }
+ l->name = nil;
+ return m;
+}
+
+void
+retnstr(char *s, int n, String **d)
+{
+ String *s1;
+
+ s1 = H;
+ if(n != 0)
+ s1 = c2string(s, n);
+ destroy(*d);
+ *d = s1;
+}
+
+void
+retstr(char *s, String **d)
+{
+ String *s1;
+
+ s1 = H;
+ if(s != nil)
+ s1 = c2string(s, strlen(s));
+ destroy(*d);
+ *d = s1;
+}
+
+Array*
+mem2array(void *va, int n)
+{
+ Heap *h;
+ Array *a;
+
+ if(n < 0)
+ n = 0;
+ h = nheap(sizeof(Array)+n);
+ h->t = &Tarray;
+ h->t->ref++;
+ a = H2D(Array*, h);
+ a->t = &Tbyte;
+ Tbyte.ref++;
+ a->len = n;
+ a->root = H;
+ a->data = (uchar*)a+sizeof(Array);
+ if(va != 0)
+ memmove(a->data, va, n);
+
+ return a;
+}
+
+static int
+utfnleng(char *s, int nb, int *ngood)
+{
+ int c;
+ long n;
+ Rune rune;
+ char *es, *starts;
+
+ starts = s;
+ es = s+nb;
+ for(n = 0; s < es; n++) {
+ c = *(uchar*)s;
+ if(c < Runeself)
+ s++;
+ else {
+ if(s+UTFmax<=es || fullrune(s, es-s))
+ s += chartorune(&rune, s);
+ else
+ break;
+ }
+ }
+ if(ngood)
+ *ngood = s-starts;
+ return n;
+}
diff --git a/libinterp/runt.h b/libinterp/runt.h
new file mode 100644
index 00000000..f7577f6a
--- /dev/null
+++ b/libinterp/runt.h
@@ -0,0 +1,3919 @@
+#pragma hjdicks x4
+#pragma pack x4
+typedef struct Sys_Qid Sys_Qid;
+typedef struct Sys_Dir Sys_Dir;
+typedef struct Sys_FD Sys_FD;
+typedef struct Sys_Connection Sys_Connection;
+typedef struct Sys_FileIO Sys_FileIO;
+typedef struct Draw_Chans Draw_Chans;
+typedef struct Draw_Point Draw_Point;
+typedef struct Draw_Rect Draw_Rect;
+typedef struct Draw_Image Draw_Image;
+typedef struct Draw_Display Draw_Display;
+typedef struct Draw_Font Draw_Font;
+typedef struct Draw_Screen Draw_Screen;
+typedef struct Draw_Pointer Draw_Pointer;
+typedef struct Draw_Context Draw_Context;
+typedef struct Draw_Wmcontext Draw_Wmcontext;
+typedef struct Prefab_Style Prefab_Style;
+typedef struct Prefab_Environ Prefab_Environ;
+typedef struct Prefab_Layout Prefab_Layout;
+typedef struct Prefab_Element Prefab_Element;
+typedef struct Prefab_Compound Prefab_Compound;
+typedef struct Tk_Toplevel Tk_Toplevel;
+typedef struct Keyring_IPint Keyring_IPint;
+typedef struct Keyring_SigAlg Keyring_SigAlg;
+typedef struct Keyring_PK Keyring_PK;
+typedef struct Keyring_SK Keyring_SK;
+typedef struct Keyring_Certificate Keyring_Certificate;
+typedef struct Keyring_DigestState Keyring_DigestState;
+typedef struct Keyring_AESstate Keyring_AESstate;
+typedef struct Keyring_DESstate Keyring_DESstate;
+typedef struct Keyring_IDEAstate Keyring_IDEAstate;
+typedef struct Keyring_RC4state Keyring_RC4state;
+typedef struct Keyring_Authinfo Keyring_Authinfo;
+typedef struct Loader_Inst Loader_Inst;
+typedef struct Loader_Typedesc Loader_Typedesc;
+typedef struct Loader_Link Loader_Link;
+typedef struct Loader_Niladt Loader_Niladt;
+typedef struct Freetype_Matrix Freetype_Matrix;
+typedef struct Freetype_Vector Freetype_Vector;
+typedef struct Freetype_Face Freetype_Face;
+typedef struct Freetype_Glyph Freetype_Glyph;
+struct Sys_Qid
+{
+ LONG path;
+ WORD vers;
+ WORD qtype;
+};
+#define Sys_Qid_size 16
+#define Sys_Qid_map {0}
+struct Sys_Dir
+{
+ String* name;
+ String* uid;
+ String* gid;
+ String* muid;
+ Sys_Qid qid;
+ WORD mode;
+ WORD atime;
+ WORD mtime;
+ uchar _pad44[4];
+ LONG length;
+ WORD dtype;
+ WORD dev;
+};
+#define Sys_Dir_size 64
+#define Sys_Dir_map {0xf0,}
+struct Sys_FD
+{
+ WORD fd;
+};
+#define Sys_FD_size 4
+#define Sys_FD_map {0}
+struct Sys_Connection
+{
+ Sys_FD* dfd;
+ Sys_FD* cfd;
+ String* dir;
+};
+#define Sys_Connection_size 12
+#define Sys_Connection_map {0xe0,}
+typedef struct{ Array* t0; String* t1; } Sys_Rread;
+#define Sys_Rread_size 8
+#define Sys_Rread_map {0xc0,}
+typedef struct{ WORD t0; String* t1; } Sys_Rwrite;
+#define Sys_Rwrite_size 8
+#define Sys_Rwrite_map {0x40,}
+struct Sys_FileIO
+{
+ Channel* read;
+ Channel* write;
+};
+typedef struct{ WORD t0; WORD t1; WORD t2; Channel* t3; } Sys_FileIO_read;
+#define Sys_FileIO_read_size 16
+#define Sys_FileIO_read_map {0x10,}
+typedef struct{ WORD t0; Array* t1; WORD t2; Channel* t3; } Sys_FileIO_write;
+#define Sys_FileIO_write_size 16
+#define Sys_FileIO_write_map {0x50,}
+#define Sys_FileIO_size 8
+#define Sys_FileIO_map {0xc0,}
+struct Draw_Chans
+{
+ WORD desc;
+};
+#define Draw_Chans_size 4
+#define Draw_Chans_map {0}
+struct Draw_Point
+{
+ WORD x;
+ WORD y;
+};
+#define Draw_Point_size 8
+#define Draw_Point_map {0}
+struct Draw_Rect
+{
+ Draw_Point min;
+ Draw_Point max;
+};
+#define Draw_Rect_size 16
+#define Draw_Rect_map {0}
+struct Draw_Image
+{
+ Draw_Rect r;
+ Draw_Rect clipr;
+ WORD depth;
+ Draw_Chans chans;
+ WORD repl;
+ Draw_Display* display;
+ Draw_Screen* screen;
+ String* iname;
+};
+#define Draw_Image_size 56
+#define Draw_Image_map {0x0,0x1c,}
+struct Draw_Display
+{
+ Draw_Image* image;
+ Draw_Image* white;
+ Draw_Image* black;
+ Draw_Image* opaque;
+ Draw_Image* transparent;
+};
+#define Draw_Display_size 20
+#define Draw_Display_map {0xf8,}
+struct Draw_Font
+{
+ String* name;
+ WORD height;
+ WORD ascent;
+ Draw_Display* display;
+};
+#define Draw_Font_size 16
+#define Draw_Font_map {0x90,}
+struct Draw_Screen
+{
+ WORD id;
+ Draw_Image* image;
+ Draw_Image* fill;
+ Draw_Display* display;
+};
+#define Draw_Screen_size 16
+#define Draw_Screen_map {0x70,}
+struct Draw_Pointer
+{
+ WORD buttons;
+ Draw_Point xy;
+ WORD msec;
+};
+#define Draw_Pointer_size 16
+#define Draw_Pointer_map {0}
+struct Draw_Context
+{
+ Draw_Display* display;
+ Draw_Screen* screen;
+ Channel* wm;
+};
+typedef struct{ String* t0; Channel* t1; } Draw_Context_wm;
+#define Draw_Context_wm_size 8
+#define Draw_Context_wm_map {0xc0,}
+#define Draw_Context_size 12
+#define Draw_Context_map {0xe0,}
+struct Draw_Wmcontext
+{
+ Channel* kbd;
+ Channel* ptr;
+ Channel* ctl;
+ Channel* wctl;
+ Channel* images;
+ Sys_FD* connfd;
+ Draw_Context* ctxt;
+};
+typedef WORD Draw_Wmcontext_kbd;
+#define Draw_Wmcontext_kbd_size 4
+#define Draw_Wmcontext_kbd_map {0}
+typedef Draw_Pointer* Draw_Wmcontext_ptr;
+#define Draw_Wmcontext_ptr_size 4
+#define Draw_Wmcontext_ptr_map {0x80,}
+typedef String* Draw_Wmcontext_ctl;
+#define Draw_Wmcontext_ctl_size 4
+#define Draw_Wmcontext_ctl_map {0x80,}
+typedef String* Draw_Wmcontext_wctl;
+#define Draw_Wmcontext_wctl_size 4
+#define Draw_Wmcontext_wctl_map {0x80,}
+typedef Draw_Image* Draw_Wmcontext_images;
+#define Draw_Wmcontext_images_size 4
+#define Draw_Wmcontext_images_map {0x80,}
+#define Draw_Wmcontext_size 28
+#define Draw_Wmcontext_map {0xfe,}
+struct Prefab_Style
+{
+ Draw_Font* titlefont;
+ Draw_Font* textfont;
+ Draw_Image* elemcolor;
+ Draw_Image* edgecolor;
+ Draw_Image* titlecolor;
+ Draw_Image* textcolor;
+ Draw_Image* highlightcolor;
+};
+#define Prefab_Style_size 28
+#define Prefab_Style_map {0xfe,}
+struct Prefab_Environ
+{
+ Draw_Screen* screen;
+ Prefab_Style* style;
+};
+#define Prefab_Environ_size 8
+#define Prefab_Environ_map {0xc0,}
+struct Prefab_Layout
+{
+ Draw_Font* font;
+ Draw_Image* color;
+ String* text;
+ Draw_Image* icon;
+ Draw_Image* mask;
+ String* tag;
+};
+#define Prefab_Layout_size 24
+#define Prefab_Layout_map {0xfc,}
+struct Prefab_Element
+{
+ WORD kind;
+ Draw_Rect r;
+ Prefab_Environ* environ;
+ String* tag;
+ List* kids;
+ String* str;
+ Draw_Image* mask;
+ Draw_Image* image;
+ Draw_Font* font;
+};
+#define Prefab_Element_size 48
+#define Prefab_Element_map {0x7,0xf0,}
+struct Prefab_Compound
+{
+ Draw_Image* image;
+ Prefab_Environ* environ;
+ Draw_Rect r;
+ Prefab_Element* title;
+ Prefab_Element* contents;
+};
+#define Prefab_Compound_size 32
+#define Prefab_Compound_map {0xc3,}
+struct Tk_Toplevel
+{
+ Draw_Display* display;
+ Channel* wreq;
+ Draw_Image* image;
+ Draw_Wmcontext* ctxt;
+ Draw_Rect screenr;
+};
+typedef String* Tk_Toplevel_wreq;
+#define Tk_Toplevel_wreq_size 4
+#define Tk_Toplevel_wreq_map {0x80,}
+#define Tk_Toplevel_size 32
+#define Tk_Toplevel_map {0xf0,}
+struct Keyring_IPint
+{
+ WORD x;
+};
+#define Keyring_IPint_size 4
+#define Keyring_IPint_map {0}
+struct Keyring_SigAlg
+{
+ String* name;
+};
+#define Keyring_SigAlg_size 4
+#define Keyring_SigAlg_map {0x80,}
+struct Keyring_PK
+{
+ Keyring_SigAlg* sa;
+ String* owner;
+};
+#define Keyring_PK_size 8
+#define Keyring_PK_map {0xc0,}
+struct Keyring_SK
+{
+ Keyring_SigAlg* sa;
+ String* owner;
+};
+#define Keyring_SK_size 8
+#define Keyring_SK_map {0xc0,}
+struct Keyring_Certificate
+{
+ Keyring_SigAlg* sa;
+ String* ha;
+ String* signer;
+ WORD exp;
+};
+#define Keyring_Certificate_size 16
+#define Keyring_Certificate_map {0xe0,}
+struct Keyring_DigestState
+{
+ WORD x;
+};
+#define Keyring_DigestState_size 4
+#define Keyring_DigestState_map {0}
+struct Keyring_AESstate
+{
+ WORD x;
+};
+#define Keyring_AESstate_size 4
+#define Keyring_AESstate_map {0}
+struct Keyring_DESstate
+{
+ WORD x;
+};
+#define Keyring_DESstate_size 4
+#define Keyring_DESstate_map {0}
+struct Keyring_IDEAstate
+{
+ WORD x;
+};
+#define Keyring_IDEAstate_size 4
+#define Keyring_IDEAstate_map {0}
+struct Keyring_RC4state
+{
+ WORD x;
+};
+#define Keyring_RC4state_size 4
+#define Keyring_RC4state_map {0}
+struct Keyring_Authinfo
+{
+ Keyring_SK* mysk;
+ Keyring_PK* mypk;
+ Keyring_Certificate* cert;
+ Keyring_PK* spk;
+ Keyring_IPint* alpha;
+ Keyring_IPint* p;
+};
+#define Keyring_Authinfo_size 24
+#define Keyring_Authinfo_map {0xfc,}
+struct Loader_Inst
+{
+ BYTE op;
+ BYTE addr;
+ uchar _pad2[2];
+ WORD src;
+ WORD mid;
+ WORD dst;
+};
+#define Loader_Inst_size 16
+#define Loader_Inst_map {0}
+struct Loader_Typedesc
+{
+ WORD size;
+ Array* map;
+};
+#define Loader_Typedesc_size 8
+#define Loader_Typedesc_map {0x40,}
+struct Loader_Link
+{
+ String* name;
+ WORD sig;
+ WORD pc;
+ WORD tdesc;
+};
+#define Loader_Link_size 16
+#define Loader_Link_map {0x80,}
+struct Loader_Niladt
+{
+ char dummy[1];
+ uchar _pad1[3];
+};
+#define Loader_Niladt_size 4
+#define Loader_Niladt_map {0}
+struct Freetype_Matrix
+{
+ WORD a;
+ WORD b;
+ WORD c;
+ WORD d;
+};
+#define Freetype_Matrix_size 16
+#define Freetype_Matrix_map {0}
+struct Freetype_Vector
+{
+ WORD dx;
+ WORD dy;
+};
+#define Freetype_Vector_size 8
+#define Freetype_Vector_map {0}
+struct Freetype_Face
+{
+ WORD nfaces;
+ WORD index;
+ WORD style;
+ WORD height;
+ WORD ascent;
+ String* familyname;
+ String* stylename;
+};
+#define Freetype_Face_size 28
+#define Freetype_Face_map {0x6,}
+struct Freetype_Glyph
+{
+ WORD top;
+ WORD left;
+ WORD height;
+ WORD width;
+ Draw_Point advance;
+ Array* bitmap;
+};
+#define Freetype_Glyph_size 28
+#define Freetype_Glyph_map {0x2,}
+void Sys_announce(void*);
+typedef struct F_Sys_announce F_Sys_announce;
+struct F_Sys_announce
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; Sys_Connection t1; }* ret;
+ uchar temps[12];
+ String* addr;
+};
+void Sys_aprint(void*);
+typedef struct F_Sys_aprint F_Sys_aprint;
+struct F_Sys_aprint
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ String* s;
+ WORD vargs;
+};
+void Sys_bind(void*);
+typedef struct F_Sys_bind F_Sys_bind;
+struct F_Sys_bind
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* s;
+ String* on;
+ WORD flags;
+};
+void Sys_byte2char(void*);
+typedef struct F_Sys_byte2char F_Sys_byte2char;
+struct F_Sys_byte2char
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; WORD t1; WORD t2; }* ret;
+ uchar temps[12];
+ Array* buf;
+ WORD n;
+};
+void Sys_char2byte(void*);
+typedef struct F_Sys_char2byte F_Sys_char2byte;
+struct F_Sys_char2byte
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD c;
+ Array* buf;
+ WORD n;
+};
+void Sys_chdir(void*);
+typedef struct F_Sys_chdir F_Sys_chdir;
+struct F_Sys_chdir
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* path;
+};
+void Sys_create(void*);
+typedef struct F_Sys_create F_Sys_create;
+struct F_Sys_create
+{
+ WORD regs[NREG-1];
+ Sys_FD** ret;
+ uchar temps[12];
+ String* s;
+ WORD mode;
+ WORD perm;
+};
+void Sys_dial(void*);
+typedef struct F_Sys_dial F_Sys_dial;
+struct F_Sys_dial
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; Sys_Connection t1; }* ret;
+ uchar temps[12];
+ String* addr;
+ String* local;
+};
+void Sys_dirread(void*);
+typedef struct F_Sys_dirread F_Sys_dirread;
+struct F_Sys_dirread
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; Array* t1; }* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Sys_dup(void*);
+typedef struct F_Sys_dup F_Sys_dup;
+struct F_Sys_dup
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD old;
+ WORD new;
+};
+void Sys_export(void*);
+typedef struct F_Sys_export F_Sys_export;
+struct F_Sys_export
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* c;
+ String* dir;
+ WORD flag;
+};
+void Sys_fauth(void*);
+typedef struct F_Sys_fauth F_Sys_fauth;
+struct F_Sys_fauth
+{
+ WORD regs[NREG-1];
+ Sys_FD** ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ String* aname;
+};
+void Sys_fd2path(void*);
+typedef struct F_Sys_fd2path F_Sys_fd2path;
+struct F_Sys_fd2path
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Sys_fildes(void*);
+typedef struct F_Sys_fildes F_Sys_fildes;
+struct F_Sys_fildes
+{
+ WORD regs[NREG-1];
+ Sys_FD** ret;
+ uchar temps[12];
+ WORD fd;
+};
+void Sys_file2chan(void*);
+typedef struct F_Sys_file2chan F_Sys_file2chan;
+struct F_Sys_file2chan
+{
+ WORD regs[NREG-1];
+ Sys_FileIO** ret;
+ uchar temps[12];
+ String* dir;
+ String* file;
+};
+void Sys_fprint(void*);
+typedef struct F_Sys_fprint F_Sys_fprint;
+struct F_Sys_fprint
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ String* s;
+ WORD vargs;
+};
+void Sys_fstat(void*);
+typedef struct F_Sys_fstat F_Sys_fstat;
+struct F_Sys_fstat
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; uchar _pad4[4]; Sys_Dir t1; }* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Sys_fversion(void*);
+typedef struct F_Sys_fversion F_Sys_fversion;
+struct F_Sys_fversion
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; String* t1; }* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ WORD msize;
+ String* version;
+};
+void Sys_fwstat(void*);
+typedef struct F_Sys_fwstat F_Sys_fwstat;
+struct F_Sys_fwstat
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ uchar _pad36[4];
+ Sys_Dir d;
+};
+void Sys_iounit(void*);
+typedef struct F_Sys_iounit F_Sys_iounit;
+struct F_Sys_iounit
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Sys_listen(void*);
+typedef struct F_Sys_listen F_Sys_listen;
+struct F_Sys_listen
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; Sys_Connection t1; }* ret;
+ uchar temps[12];
+ Sys_Connection c;
+};
+void Sys_millisec(void*);
+typedef struct F_Sys_millisec F_Sys_millisec;
+struct F_Sys_millisec
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+};
+void Sys_mount(void*);
+typedef struct F_Sys_mount F_Sys_mount;
+struct F_Sys_mount
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Sys_FD* afd;
+ String* on;
+ WORD flags;
+ String* spec;
+};
+void Sys_open(void*);
+typedef struct F_Sys_open F_Sys_open;
+struct F_Sys_open
+{
+ WORD regs[NREG-1];
+ Sys_FD** ret;
+ uchar temps[12];
+ String* s;
+ WORD mode;
+};
+void Sys_pctl(void*);
+typedef struct F_Sys_pctl F_Sys_pctl;
+struct F_Sys_pctl
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD flags;
+ List* movefd;
+};
+void Sys_pipe(void*);
+typedef struct F_Sys_pipe F_Sys_pipe;
+struct F_Sys_pipe
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Array* fds;
+};
+void Sys_pread(void*);
+typedef struct F_Sys_pread F_Sys_pread;
+struct F_Sys_pread
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Array* buf;
+ WORD n;
+ uchar _pad44[4];
+ LONG off;
+};
+void Sys_print(void*);
+typedef struct F_Sys_print F_Sys_print;
+struct F_Sys_print
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* s;
+ WORD vargs;
+};
+void Sys_pwrite(void*);
+typedef struct F_Sys_pwrite F_Sys_pwrite;
+struct F_Sys_pwrite
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Array* buf;
+ WORD n;
+ uchar _pad44[4];
+ LONG off;
+};
+void Sys_read(void*);
+typedef struct F_Sys_read F_Sys_read;
+struct F_Sys_read
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Array* buf;
+ WORD n;
+};
+void Sys_remove(void*);
+typedef struct F_Sys_remove F_Sys_remove;
+struct F_Sys_remove
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* s;
+};
+void Sys_seek(void*);
+typedef struct F_Sys_seek F_Sys_seek;
+struct F_Sys_seek
+{
+ WORD regs[NREG-1];
+ LONG* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ uchar _pad36[4];
+ LONG off;
+ WORD start;
+};
+void Sys_sleep(void*);
+typedef struct F_Sys_sleep F_Sys_sleep;
+struct F_Sys_sleep
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD period;
+};
+void Sys_sprint(void*);
+typedef struct F_Sys_sprint F_Sys_sprint;
+struct F_Sys_sprint
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ String* s;
+ WORD vargs;
+};
+void Sys_stat(void*);
+typedef struct F_Sys_stat F_Sys_stat;
+struct F_Sys_stat
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; uchar _pad4[4]; Sys_Dir t1; }* ret;
+ uchar temps[12];
+ String* s;
+};
+void Sys_stream(void*);
+typedef struct F_Sys_stream F_Sys_stream;
+struct F_Sys_stream
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* src;
+ Sys_FD* dst;
+ WORD bufsiz;
+};
+void Sys_tokenize(void*);
+typedef struct F_Sys_tokenize F_Sys_tokenize;
+struct F_Sys_tokenize
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; List* t1; }* ret;
+ uchar temps[12];
+ String* s;
+ String* delim;
+};
+void Sys_unmount(void*);
+typedef struct F_Sys_unmount F_Sys_unmount;
+struct F_Sys_unmount
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* s1;
+ String* s2;
+};
+void Sys_utfbytes(void*);
+typedef struct F_Sys_utfbytes F_Sys_utfbytes;
+struct F_Sys_utfbytes
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Array* buf;
+ WORD n;
+};
+void Sys_werrstr(void*);
+typedef struct F_Sys_werrstr F_Sys_werrstr;
+struct F_Sys_werrstr
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* s;
+};
+void Sys_write(void*);
+typedef struct F_Sys_write F_Sys_write;
+struct F_Sys_write
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Array* buf;
+ WORD n;
+};
+void Sys_wstat(void*);
+typedef struct F_Sys_wstat F_Sys_wstat;
+struct F_Sys_wstat
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* s;
+ uchar _pad36[4];
+ Sys_Dir d;
+};
+#define Sys_PATH "$Sys"
+#define Sys_Maxint 2147483647
+#define Sys_QTDIR 128
+#define Sys_QTAPPEND 64
+#define Sys_QTEXCL 32
+#define Sys_QTAUTH 8
+#define Sys_QTTMP 4
+#define Sys_QTFILE 0
+#define Sys_ATOMICIO 8192
+#define Sys_SEEKSTART 0
+#define Sys_SEEKRELA 1
+#define Sys_SEEKEND 2
+#define Sys_NAMEMAX 256
+#define Sys_ERRMAX 128
+#define Sys_WAITLEN 192
+#define Sys_OREAD 0
+#define Sys_OWRITE 1
+#define Sys_ORDWR 2
+#define Sys_OTRUNC 16
+#define Sys_ORCLOSE 64
+#define Sys_OEXCL 4096
+#define Sys_DMDIR -2147483648
+#define Sys_DMAPPEND 1073741824
+#define Sys_DMEXCL 536870912
+#define Sys_DMAUTH 134217728
+#define Sys_DMTMP 67108864
+#define Sys_MREPL 0
+#define Sys_MBEFORE 1
+#define Sys_MAFTER 2
+#define Sys_MCREATE 4
+#define Sys_MCACHE 16
+#define Sys_NEWFD 1
+#define Sys_FORKFD 2
+#define Sys_NEWNS 4
+#define Sys_FORKNS 8
+#define Sys_NEWPGRP 16
+#define Sys_NODEVS 32
+#define Sys_NEWENV 64
+#define Sys_FORKENV 128
+#define Sys_EXPWAIT 0
+#define Sys_EXPASYNC 1
+#define Sys_UTFmax 3
+#define Sys_UTFerror 128
+void Rect_Xrect(void*);
+typedef struct F_Rect_Xrect F_Rect_Xrect;
+struct F_Rect_Xrect
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Rect s;
+};
+void Point_add(void*);
+typedef struct F_Point_add F_Point_add;
+struct F_Point_add
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Point p;
+ Draw_Point q;
+};
+void Rect_addpt(void*);
+typedef struct F_Rect_addpt F_Rect_addpt;
+struct F_Rect_addpt
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Point p;
+};
+void Display_allocate(void*);
+typedef struct F_Display_allocate F_Display_allocate;
+struct F_Display_allocate
+{
+ WORD regs[NREG-1];
+ Draw_Display** ret;
+ uchar temps[12];
+ String* dev;
+};
+void Screen_allocate(void*);
+typedef struct F_Screen_allocate F_Screen_allocate;
+struct F_Screen_allocate
+{
+ WORD regs[NREG-1];
+ Draw_Screen** ret;
+ uchar temps[12];
+ Draw_Image* image;
+ Draw_Image* fill;
+ WORD public;
+};
+void Image_arc(void*);
+typedef struct F_Image_arc F_Image_arc;
+struct F_Image_arc
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ WORD thick;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD alpha;
+ WORD phi;
+};
+void Image_arcop(void*);
+typedef struct F_Image_arcop F_Image_arcop;
+struct F_Image_arcop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ WORD thick;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD alpha;
+ WORD phi;
+ WORD op;
+};
+void Image_arrow(void*);
+typedef struct F_Image_arrow F_Image_arrow;
+struct F_Image_arrow
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD a;
+ WORD b;
+ WORD c;
+};
+void Font_bbox(void*);
+typedef struct F_Font_bbox F_Font_bbox;
+struct F_Font_bbox
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Draw_Font* f;
+ String* str;
+};
+void Image_bezier(void*);
+typedef struct F_Image_bezier F_Image_bezier;
+struct F_Image_bezier
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point a;
+ Draw_Point b;
+ Draw_Point c;
+ Draw_Point d;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_bezierop(void*);
+typedef struct F_Image_bezierop F_Image_bezierop;
+struct F_Image_bezierop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point a;
+ Draw_Point b;
+ Draw_Point c;
+ Draw_Point d;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Image_bezspline(void*);
+typedef struct F_Image_bezspline F_Image_bezspline;
+struct F_Image_bezspline
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_bezsplineop(void*);
+typedef struct F_Image_bezsplineop F_Image_bezsplineop;
+struct F_Image_bezsplineop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Image_border(void*);
+typedef struct F_Image_border F_Image_border;
+struct F_Image_border
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Rect r;
+ WORD i;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_bottom(void*);
+typedef struct F_Image_bottom F_Image_bottom;
+struct F_Image_bottom
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* win;
+};
+void Screen_bottom(void*);
+typedef struct F_Screen_bottom F_Screen_bottom;
+struct F_Screen_bottom
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Screen* screen;
+ Array* wins;
+};
+void Font_build(void*);
+typedef struct F_Font_build F_Font_build;
+struct F_Font_build
+{
+ WORD regs[NREG-1];
+ Draw_Font** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ String* name;
+ String* desc;
+};
+void Draw_bytesperline(void*);
+typedef struct F_Draw_bytesperline F_Draw_bytesperline;
+struct F_Draw_bytesperline
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ WORD d;
+};
+void Rect_canon(void*);
+typedef struct F_Rect_canon F_Rect_canon;
+struct F_Rect_canon
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Draw_Rect r;
+};
+void Rect_clip(void*);
+typedef struct F_Rect_clip F_Rect_clip;
+struct F_Rect_clip
+{
+ WORD regs[NREG-1];
+ struct{ Draw_Rect t0; WORD t1; }* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Rect s;
+};
+void Display_cmap2rgb(void*);
+typedef struct F_Display_cmap2rgb F_Display_cmap2rgb;
+struct F_Display_cmap2rgb
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; WORD t1; WORD t2; }* ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD c;
+};
+void Display_cmap2rgba(void*);
+typedef struct F_Display_cmap2rgba F_Display_cmap2rgba;
+struct F_Display_cmap2rgba
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD c;
+};
+void Display_color(void*);
+typedef struct F_Display_color F_Display_color;
+struct F_Display_color
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD color;
+};
+void Display_colormix(void*);
+typedef struct F_Display_colormix F_Display_colormix;
+struct F_Display_colormix
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD c1;
+ WORD c2;
+};
+void Rect_combine(void*);
+typedef struct F_Rect_combine F_Rect_combine;
+struct F_Rect_combine
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Rect s;
+};
+void Rect_contains(void*);
+typedef struct F_Rect_contains F_Rect_contains;
+struct F_Rect_contains
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Point p;
+};
+void Chans_depth(void*);
+typedef struct F_Chans_depth F_Chans_depth;
+struct F_Chans_depth
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Chans c;
+};
+void Point_div(void*);
+typedef struct F_Point_div F_Point_div;
+struct F_Point_div
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Point p;
+ WORD i;
+};
+void Image_draw(void*);
+typedef struct F_Image_draw F_Image_draw;
+struct F_Image_draw
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Rect r;
+ Draw_Image* src;
+ Draw_Image* matte;
+ Draw_Point p;
+};
+void Image_drawop(void*);
+typedef struct F_Image_drawop F_Image_drawop;
+struct F_Image_drawop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Rect r;
+ Draw_Image* src;
+ Draw_Image* matte;
+ Draw_Point p;
+ WORD op;
+};
+void Rect_dx(void*);
+typedef struct F_Rect_dx F_Rect_dx;
+struct F_Rect_dx
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+};
+void Rect_dy(void*);
+typedef struct F_Rect_dy F_Rect_dy;
+struct F_Rect_dy
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+};
+void Image_ellipse(void*);
+typedef struct F_Image_ellipse F_Image_ellipse;
+struct F_Image_ellipse
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ WORD thick;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_ellipseop(void*);
+typedef struct F_Image_ellipseop F_Image_ellipseop;
+struct F_Image_ellipseop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ WORD thick;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Chans_eq(void*);
+typedef struct F_Chans_eq F_Chans_eq;
+struct F_Chans_eq
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Chans c;
+ Draw_Chans d;
+};
+void Point_eq(void*);
+typedef struct F_Point_eq F_Point_eq;
+struct F_Point_eq
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Point p;
+ Draw_Point q;
+};
+void Rect_eq(void*);
+typedef struct F_Rect_eq F_Rect_eq;
+struct F_Rect_eq
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Rect s;
+};
+void Image_fillarc(void*);
+typedef struct F_Image_fillarc F_Image_fillarc;
+struct F_Image_fillarc
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD alpha;
+ WORD phi;
+};
+void Image_fillarcop(void*);
+typedef struct F_Image_fillarcop F_Image_fillarcop;
+struct F_Image_fillarcop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD alpha;
+ WORD phi;
+ WORD op;
+};
+void Image_fillbezier(void*);
+typedef struct F_Image_fillbezier F_Image_fillbezier;
+struct F_Image_fillbezier
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point a;
+ Draw_Point b;
+ Draw_Point c;
+ Draw_Point d;
+ WORD wind;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_fillbezierop(void*);
+typedef struct F_Image_fillbezierop F_Image_fillbezierop;
+struct F_Image_fillbezierop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point a;
+ Draw_Point b;
+ Draw_Point c;
+ Draw_Point d;
+ WORD wind;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Image_fillbezspline(void*);
+typedef struct F_Image_fillbezspline F_Image_fillbezspline;
+struct F_Image_fillbezspline
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD wind;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_fillbezsplineop(void*);
+typedef struct F_Image_fillbezsplineop F_Image_fillbezsplineop;
+struct F_Image_fillbezsplineop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD wind;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Image_fillellipse(void*);
+typedef struct F_Image_fillellipse F_Image_fillellipse;
+struct F_Image_fillellipse
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_fillellipseop(void*);
+typedef struct F_Image_fillellipseop F_Image_fillellipseop;
+struct F_Image_fillellipseop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point c;
+ WORD a;
+ WORD b;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Image_fillpoly(void*);
+typedef struct F_Image_fillpoly F_Image_fillpoly;
+struct F_Image_fillpoly
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD wind;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_fillpolyop(void*);
+typedef struct F_Image_fillpolyop F_Image_fillpolyop;
+struct F_Image_fillpolyop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD wind;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Image_flush(void*);
+typedef struct F_Image_flush F_Image_flush;
+struct F_Image_flush
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* win;
+ WORD func;
+};
+void Image_gendraw(void*);
+typedef struct F_Image_gendraw F_Image_gendraw;
+struct F_Image_gendraw
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Rect r;
+ Draw_Image* src;
+ Draw_Point p0;
+ Draw_Image* matte;
+ Draw_Point p1;
+};
+void Image_gendrawop(void*);
+typedef struct F_Image_gendrawop F_Image_gendrawop;
+struct F_Image_gendrawop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Rect r;
+ Draw_Image* src;
+ Draw_Point p0;
+ Draw_Image* matte;
+ Draw_Point p1;
+ WORD op;
+};
+void Display_getwindow(void*);
+typedef struct F_Display_getwindow F_Display_getwindow;
+struct F_Display_getwindow
+{
+ WORD regs[NREG-1];
+ struct{ Draw_Screen* t0; Draw_Image* t1; }* ret;
+ uchar temps[12];
+ Draw_Display* d;
+ String* winname;
+ Draw_Screen* screen;
+ Draw_Image* image;
+ WORD backup;
+};
+void Draw_icossin(void*);
+typedef struct F_Draw_icossin F_Draw_icossin;
+struct F_Draw_icossin
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; WORD t1; }* ret;
+ uchar temps[12];
+ WORD deg;
+};
+void Draw_icossin2(void*);
+typedef struct F_Draw_icossin2 F_Draw_icossin2;
+struct F_Draw_icossin2
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; WORD t1; }* ret;
+ uchar temps[12];
+ Draw_Point p;
+};
+void Point_in(void*);
+typedef struct F_Point_in F_Point_in;
+struct F_Point_in
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Point p;
+ Draw_Rect r;
+};
+void Rect_inrect(void*);
+typedef struct F_Rect_inrect F_Rect_inrect;
+struct F_Rect_inrect
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Rect s;
+};
+void Rect_inset(void*);
+typedef struct F_Rect_inset F_Rect_inset;
+struct F_Rect_inset
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ WORD n;
+};
+void Image_line(void*);
+typedef struct F_Image_line F_Image_line;
+struct F_Image_line
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point p0;
+ Draw_Point p1;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_lineop(void*);
+typedef struct F_Image_lineop F_Image_lineop;
+struct F_Image_lineop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point p0;
+ Draw_Point p1;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Chans_mk(void*);
+typedef struct F_Chans_mk F_Chans_mk;
+struct F_Chans_mk
+{
+ WORD regs[NREG-1];
+ Draw_Chans* ret;
+ uchar temps[12];
+ String* s;
+};
+void Point_mul(void*);
+typedef struct F_Point_mul F_Point_mul;
+struct F_Point_mul
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Point p;
+ WORD i;
+};
+void Image_name(void*);
+typedef struct F_Image_name F_Image_name;
+struct F_Image_name
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Image* src;
+ String* name;
+ WORD in;
+};
+void Display_namedimage(void*);
+typedef struct F_Display_namedimage F_Display_namedimage;
+struct F_Display_namedimage
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ String* name;
+};
+void Display_newimage(void*);
+typedef struct F_Display_newimage F_Display_newimage;
+struct F_Display_newimage
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ Draw_Rect r;
+ Draw_Chans chans;
+ WORD repl;
+ WORD color;
+};
+void Screen_newwindow(void*);
+typedef struct F_Screen_newwindow F_Screen_newwindow;
+struct F_Screen_newwindow
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Screen* screen;
+ Draw_Rect r;
+ WORD backing;
+ WORD color;
+};
+void Display_open(void*);
+typedef struct F_Display_open F_Display_open;
+struct F_Display_open
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ String* name;
+};
+void Font_open(void*);
+typedef struct F_Font_open F_Font_open;
+struct F_Font_open
+{
+ WORD regs[NREG-1];
+ Draw_Font** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ String* name;
+};
+void Image_origin(void*);
+typedef struct F_Image_origin F_Image_origin;
+struct F_Image_origin
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Image* win;
+ Draw_Point log;
+ Draw_Point scr;
+};
+void Image_poly(void*);
+typedef struct F_Image_poly F_Image_poly;
+struct F_Image_poly
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+};
+void Image_polyop(void*);
+typedef struct F_Image_polyop F_Image_polyop;
+struct F_Image_polyop
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Array* p;
+ WORD end0;
+ WORD end1;
+ WORD radius;
+ Draw_Image* src;
+ Draw_Point sp;
+ WORD op;
+};
+void Display_publicscreen(void*);
+typedef struct F_Display_publicscreen F_Display_publicscreen;
+struct F_Display_publicscreen
+{
+ WORD regs[NREG-1];
+ Draw_Screen** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD id;
+};
+void Display_readimage(void*);
+typedef struct F_Display_readimage F_Display_readimage;
+struct F_Display_readimage
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ Sys_FD* fd;
+};
+void Image_readpixels(void*);
+typedef struct F_Image_readpixels F_Image_readpixels;
+struct F_Image_readpixels
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Image* src;
+ Draw_Rect r;
+ Array* data;
+};
+void Display_rgb(void*);
+typedef struct F_Display_rgb F_Display_rgb;
+struct F_Display_rgb
+{
+ WORD regs[NREG-1];
+ Draw_Image** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD r;
+ WORD g;
+ WORD b;
+};
+void Display_rgb2cmap(void*);
+typedef struct F_Display_rgb2cmap F_Display_rgb2cmap;
+struct F_Display_rgb2cmap
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Display* d;
+ WORD r;
+ WORD g;
+ WORD b;
+};
+void Draw_setalpha(void*);
+typedef struct F_Draw_setalpha F_Draw_setalpha;
+struct F_Draw_setalpha
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD c;
+ WORD a;
+};
+void Rect_size(void*);
+typedef struct F_Rect_size F_Rect_size;
+struct F_Rect_size
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Rect r;
+};
+void Display_startrefresh(void*);
+typedef struct F_Display_startrefresh F_Display_startrefresh;
+struct F_Display_startrefresh
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Display* d;
+};
+void Point_sub(void*);
+typedef struct F_Point_sub F_Point_sub;
+struct F_Point_sub
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Point p;
+ Draw_Point q;
+};
+void Rect_subpt(void*);
+typedef struct F_Rect_subpt F_Rect_subpt;
+struct F_Rect_subpt
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Draw_Rect r;
+ Draw_Point p;
+};
+void Chans_text(void*);
+typedef struct F_Chans_text F_Chans_text;
+struct F_Chans_text
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Draw_Chans c;
+};
+void Image_text(void*);
+typedef struct F_Image_text F_Image_text;
+struct F_Image_text
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point p;
+ Draw_Image* src;
+ Draw_Point sp;
+ Draw_Font* font;
+ String* str;
+};
+void Image_textbg(void*);
+typedef struct F_Image_textbg F_Image_textbg;
+struct F_Image_textbg
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point p;
+ Draw_Image* src;
+ Draw_Point sp;
+ Draw_Font* font;
+ String* str;
+ Draw_Image* bg;
+ Draw_Point bgp;
+};
+void Image_textbgop(void*);
+typedef struct F_Image_textbgop F_Image_textbgop;
+struct F_Image_textbgop
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point p;
+ Draw_Image* src;
+ Draw_Point sp;
+ Draw_Font* font;
+ String* str;
+ Draw_Image* bg;
+ Draw_Point bgp;
+ WORD op;
+};
+void Image_textop(void*);
+typedef struct F_Image_textop F_Image_textop;
+struct F_Image_textop
+{
+ WORD regs[NREG-1];
+ Draw_Point* ret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Point p;
+ Draw_Image* src;
+ Draw_Point sp;
+ Draw_Font* font;
+ String* str;
+ WORD op;
+};
+void Image_top(void*);
+typedef struct F_Image_top F_Image_top;
+struct F_Image_top
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Image* win;
+};
+void Screen_top(void*);
+typedef struct F_Screen_top F_Screen_top;
+struct F_Screen_top
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Draw_Screen* screen;
+ Array* wins;
+};
+void Font_width(void*);
+typedef struct F_Font_width F_Font_width;
+struct F_Font_width
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Font* f;
+ String* str;
+};
+void Display_writeimage(void*);
+typedef struct F_Display_writeimage F_Display_writeimage;
+struct F_Display_writeimage
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Display* d;
+ Sys_FD* fd;
+ Draw_Image* i;
+};
+void Image_writepixels(void*);
+typedef struct F_Image_writepixels F_Image_writepixels;
+struct F_Image_writepixels
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Draw_Image* dst;
+ Draw_Rect r;
+ Array* data;
+};
+#define Draw_PATH "$Draw"
+#define Draw_Opaque -1
+#define Draw_Transparent 0
+#define Draw_Black 255
+#define Draw_White -1
+#define Draw_Red -16776961
+#define Draw_Green 16711935
+#define Draw_Blue 65535
+#define Draw_Cyan 16777215
+#define Draw_Magenta -16711681
+#define Draw_Yellow -65281
+#define Draw_Grey -286331137
+#define Draw_Paleyellow -21761
+#define Draw_Darkyellow -286351617
+#define Draw_Darkgreen 1149781247
+#define Draw_Palegreen -1426085121
+#define Draw_Medgreen -1999861505
+#define Draw_Darkblue 22015
+#define Draw_Palebluegreen -1426063361
+#define Draw_Paleblue 48127
+#define Draw_Bluegreen 8947967
+#define Draw_Greygreen 1437248255
+#define Draw_Palegreygreen -1628508417
+#define Draw_Yellowgreen -1718006529
+#define Draw_Medblue 39423
+#define Draw_Greyblue 6142975
+#define Draw_Palegreyblue 1234427391
+#define Draw_Purpleblue -2004300545
+#define Draw_Notacolor -256
+#define Draw_Nofill -256
+#define Draw_Endsquare 0
+#define Draw_Enddisc 1
+#define Draw_Endarrow 2
+#define Draw_Flushoff 0
+#define Draw_Flushon 1
+#define Draw_Flushnow 2
+#define Draw_Refbackup 0
+#define Draw_Refnone 1
+#define Draw_SinD 8
+#define Draw_DinS 4
+#define Draw_SoutD 2
+#define Draw_DoutS 1
+#define Draw_S 10
+#define Draw_SoverD 11
+#define Draw_SatopD 9
+#define Draw_SxorD 3
+#define Draw_D 5
+#define Draw_DoverS 7
+#define Draw_DatopS 6
+#define Draw_DxorS 3
+#define Draw_Clear 0
+#define Draw_CRed 0
+#define Draw_CGreen 1
+#define Draw_CBlue 2
+#define Draw_CGrey 3
+#define Draw_CAlpha 4
+#define Draw_CMap 5
+#define Draw_CIgnore 6
+void Element_adjust(void*);
+typedef struct F_Element_adjust F_Element_adjust;
+struct F_Element_adjust
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Element* elem;
+ WORD equal;
+ WORD dir;
+};
+void Element_append(void*);
+typedef struct F_Element_append F_Element_append;
+struct F_Element_append
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Prefab_Element* elist;
+ Prefab_Element* elem;
+};
+void Compound_box(void*);
+typedef struct F_Compound_box F_Compound_box;
+struct F_Compound_box
+{
+ WORD regs[NREG-1];
+ Prefab_Compound** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Draw_Point p;
+ Prefab_Element* title;
+ Prefab_Element* elist;
+};
+void Element_clip(void*);
+typedef struct F_Element_clip F_Element_clip;
+struct F_Element_clip
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Element* elem;
+ Draw_Rect r;
+};
+void Compound_draw(void*);
+typedef struct F_Compound_draw F_Compound_draw;
+struct F_Compound_draw
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+};
+void Element_elist(void*);
+typedef struct F_Element_elist F_Element_elist;
+struct F_Element_elist
+{
+ WORD regs[NREG-1];
+ Prefab_Element** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Prefab_Element* elem;
+ WORD kind;
+};
+void Compound_highlight(void*);
+typedef struct F_Compound_highlight F_Compound_highlight;
+struct F_Compound_highlight
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+ Prefab_Element* elem;
+ WORD on;
+};
+void Element_icon(void*);
+typedef struct F_Element_icon F_Element_icon;
+struct F_Element_icon
+{
+ WORD regs[NREG-1];
+ Prefab_Element** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Draw_Rect r;
+ Draw_Image* icon;
+ Draw_Image* mask;
+};
+void Compound_iconbox(void*);
+typedef struct F_Compound_iconbox F_Compound_iconbox;
+struct F_Compound_iconbox
+{
+ WORD regs[NREG-1];
+ Prefab_Compound** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Draw_Point p;
+ String* title;
+ Draw_Image* icon;
+ Draw_Image* mask;
+};
+void Element_layout(void*);
+typedef struct F_Element_layout F_Element_layout;
+struct F_Element_layout
+{
+ WORD regs[NREG-1];
+ Prefab_Element** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ List* lay;
+ Draw_Rect r;
+ WORD kind;
+};
+void Compound_layoutbox(void*);
+typedef struct F_Compound_layoutbox F_Compound_layoutbox;
+struct F_Compound_layoutbox
+{
+ WORD regs[NREG-1];
+ Prefab_Compound** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Draw_Rect r;
+ String* title;
+ List* lay;
+};
+void Compound_redraw(void*);
+typedef struct F_Compound_redraw F_Compound_redraw;
+struct F_Compound_redraw
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+ Draw_Rect r;
+};
+void Element_scroll(void*);
+typedef struct F_Element_scroll F_Element_scroll;
+struct F_Element_scroll
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Element* elem;
+ Draw_Point d;
+};
+void Compound_scroll(void*);
+typedef struct F_Compound_scroll F_Compound_scroll;
+struct F_Compound_scroll
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+ Prefab_Element* elem;
+ Draw_Point d;
+};
+void Compound_select(void*);
+typedef struct F_Compound_select F_Compound_select;
+struct F_Compound_select
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; WORD t1; Prefab_Element* t2; }* ret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+ Prefab_Element* elem;
+ WORD i;
+ Channel* c;
+};
+void Element_separator(void*);
+typedef struct F_Element_separator F_Element_separator;
+struct F_Element_separator
+{
+ WORD regs[NREG-1];
+ Prefab_Element** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Draw_Rect r;
+ Draw_Image* icon;
+ Draw_Image* mask;
+};
+void Element_show(void*);
+typedef struct F_Element_show F_Element_show;
+struct F_Element_show
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Prefab_Element* elist;
+ Prefab_Element* elem;
+};
+void Compound_show(void*);
+typedef struct F_Compound_show F_Compound_show;
+struct F_Compound_show
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+ Prefab_Element* elem;
+};
+void Compound_tagselect(void*);
+typedef struct F_Compound_tagselect F_Compound_tagselect;
+struct F_Compound_tagselect
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; WORD t1; Prefab_Element* t2; }* ret;
+ uchar temps[12];
+ Prefab_Compound* comp;
+ Prefab_Element* elem;
+ WORD i;
+ Channel* c;
+};
+void Element_text(void*);
+typedef struct F_Element_text F_Element_text;
+struct F_Element_text
+{
+ WORD regs[NREG-1];
+ Prefab_Element** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ String* text;
+ Draw_Rect r;
+ WORD kind;
+};
+void Compound_textbox(void*);
+typedef struct F_Compound_textbox F_Compound_textbox;
+struct F_Compound_textbox
+{
+ WORD regs[NREG-1];
+ Prefab_Compound** ret;
+ uchar temps[12];
+ Prefab_Environ* env;
+ Draw_Rect r;
+ String* title;
+ String* text;
+};
+void Element_translate(void*);
+typedef struct F_Element_translate F_Element_translate;
+struct F_Element_translate
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Prefab_Element* elem;
+ Draw_Point d;
+};
+#define Prefab_PATH "$Prefab"
+#define Prefab_EIcon 0
+#define Prefab_EText 1
+#define Prefab_ETitle 2
+#define Prefab_EHorizontal 3
+#define Prefab_EVertical 4
+#define Prefab_ESeparator 5
+#define Prefab_Adjpack 10
+#define Prefab_Adjequal 11
+#define Prefab_Adjfill 12
+#define Prefab_Adjleft 20
+#define Prefab_Adjup 20
+#define Prefab_Adjcenter 21
+#define Prefab_Adjright 22
+#define Prefab_Adjdown 22
+void Tk_cmd(void*);
+typedef struct F_Tk_cmd F_Tk_cmd;
+struct F_Tk_cmd
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ String* arg;
+};
+void Tk_color(void*);
+typedef struct F_Tk_color F_Tk_color;
+struct F_Tk_color
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* col;
+};
+void Tk_getimage(void*);
+typedef struct F_Tk_getimage F_Tk_getimage;
+struct F_Tk_getimage
+{
+ WORD regs[NREG-1];
+ struct{ Draw_Image* t0; Draw_Image* t1; String* t2; }* ret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ String* name;
+};
+void Tk_keyboard(void*);
+typedef struct F_Tk_keyboard F_Tk_keyboard;
+struct F_Tk_keyboard
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ WORD key;
+};
+void Tk_namechan(void*);
+typedef struct F_Tk_namechan F_Tk_namechan;
+struct F_Tk_namechan
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ Channel* c;
+ String* n;
+};
+void Tk_pointer(void*);
+typedef struct F_Tk_pointer F_Tk_pointer;
+struct F_Tk_pointer
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ Draw_Pointer p;
+};
+void Tk_putimage(void*);
+typedef struct F_Tk_putimage F_Tk_putimage;
+struct F_Tk_putimage
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ String* name;
+ Draw_Image* i;
+ Draw_Image* m;
+};
+void Tk_quote(void*);
+typedef struct F_Tk_quote F_Tk_quote;
+struct F_Tk_quote
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ String* s;
+};
+void Tk_rect(void*);
+typedef struct F_Tk_rect F_Tk_rect;
+struct F_Tk_rect
+{
+ WORD regs[NREG-1];
+ Draw_Rect* ret;
+ uchar temps[12];
+ Tk_Toplevel* t;
+ String* name;
+ WORD flags;
+};
+void Tk_toplevel(void*);
+typedef struct F_Tk_toplevel F_Tk_toplevel;
+struct F_Tk_toplevel
+{
+ WORD regs[NREG-1];
+ Tk_Toplevel** ret;
+ uchar temps[12];
+ Draw_Display* d;
+ String* arg;
+};
+#define Tk_PATH "$Tk"
+#define Tk_Border 1
+#define Tk_Required 2
+#define Tk_Local 4
+void Math_FPcontrol(void*);
+typedef struct F_Math_FPcontrol F_Math_FPcontrol;
+struct F_Math_FPcontrol
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD r;
+ WORD mask;
+};
+void Math_FPstatus(void*);
+typedef struct F_Math_FPstatus F_Math_FPstatus;
+struct F_Math_FPstatus
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ WORD r;
+ WORD mask;
+};
+void Math_acos(void*);
+typedef struct F_Math_acos F_Math_acos;
+struct F_Math_acos
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_acosh(void*);
+typedef struct F_Math_acosh F_Math_acosh;
+struct F_Math_acosh
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_asin(void*);
+typedef struct F_Math_asin F_Math_asin;
+struct F_Math_asin
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_asinh(void*);
+typedef struct F_Math_asinh F_Math_asinh;
+struct F_Math_asinh
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_atan(void*);
+typedef struct F_Math_atan F_Math_atan;
+struct F_Math_atan
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_atan2(void*);
+typedef struct F_Math_atan2 F_Math_atan2;
+struct F_Math_atan2
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL y;
+ REAL x;
+};
+void Math_atanh(void*);
+typedef struct F_Math_atanh F_Math_atanh;
+struct F_Math_atanh
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_bits32real(void*);
+typedef struct F_Math_bits32real F_Math_bits32real;
+struct F_Math_bits32real
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ WORD b;
+};
+void Math_bits64real(void*);
+typedef struct F_Math_bits64real F_Math_bits64real;
+struct F_Math_bits64real
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ LONG b;
+};
+void Math_cbrt(void*);
+typedef struct F_Math_cbrt F_Math_cbrt;
+struct F_Math_cbrt
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_ceil(void*);
+typedef struct F_Math_ceil F_Math_ceil;
+struct F_Math_ceil
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_copysign(void*);
+typedef struct F_Math_copysign F_Math_copysign;
+struct F_Math_copysign
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL s;
+};
+void Math_cos(void*);
+typedef struct F_Math_cos F_Math_cos;
+struct F_Math_cos
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_cosh(void*);
+typedef struct F_Math_cosh F_Math_cosh;
+struct F_Math_cosh
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_dot(void*);
+typedef struct F_Math_dot F_Math_dot;
+struct F_Math_dot
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ Array* x;
+ Array* y;
+};
+void Math_erf(void*);
+typedef struct F_Math_erf F_Math_erf;
+struct F_Math_erf
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_erfc(void*);
+typedef struct F_Math_erfc F_Math_erfc;
+struct F_Math_erfc
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_exp(void*);
+typedef struct F_Math_exp F_Math_exp;
+struct F_Math_exp
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_expm1(void*);
+typedef struct F_Math_expm1 F_Math_expm1;
+struct F_Math_expm1
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_export_int(void*);
+typedef struct F_Math_export_int F_Math_export_int;
+struct F_Math_export_int
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* b;
+ Array* x;
+};
+void Math_export_real(void*);
+typedef struct F_Math_export_real F_Math_export_real;
+struct F_Math_export_real
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* b;
+ Array* x;
+};
+void Math_export_real32(void*);
+typedef struct F_Math_export_real32 F_Math_export_real32;
+struct F_Math_export_real32
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* b;
+ Array* x;
+};
+void Math_fabs(void*);
+typedef struct F_Math_fabs F_Math_fabs;
+struct F_Math_fabs
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_fdim(void*);
+typedef struct F_Math_fdim F_Math_fdim;
+struct F_Math_fdim
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_finite(void*);
+typedef struct F_Math_finite F_Math_finite;
+struct F_Math_finite
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_floor(void*);
+typedef struct F_Math_floor F_Math_floor;
+struct F_Math_floor
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_fmax(void*);
+typedef struct F_Math_fmax F_Math_fmax;
+struct F_Math_fmax
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_fmin(void*);
+typedef struct F_Math_fmin F_Math_fmin;
+struct F_Math_fmin
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_fmod(void*);
+typedef struct F_Math_fmod F_Math_fmod;
+struct F_Math_fmod
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_gemm(void*);
+typedef struct F_Math_gemm F_Math_gemm;
+struct F_Math_gemm
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ WORD transa;
+ WORD transb;
+ WORD m;
+ WORD n;
+ WORD k;
+ uchar _pad52[4];
+ REAL alpha;
+ Array* a;
+ WORD lda;
+ Array* b;
+ WORD ldb;
+ REAL beta;
+ Array* c;
+ WORD ldc;
+};
+void Math_getFPcontrol(void*);
+typedef struct F_Math_getFPcontrol F_Math_getFPcontrol;
+struct F_Math_getFPcontrol
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+};
+void Math_getFPstatus(void*);
+typedef struct F_Math_getFPstatus F_Math_getFPstatus;
+struct F_Math_getFPstatus
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+};
+void Math_hypot(void*);
+typedef struct F_Math_hypot F_Math_hypot;
+struct F_Math_hypot
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_iamax(void*);
+typedef struct F_Math_iamax F_Math_iamax;
+struct F_Math_iamax
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Array* x;
+};
+void Math_ilogb(void*);
+typedef struct F_Math_ilogb F_Math_ilogb;
+struct F_Math_ilogb
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_import_int(void*);
+typedef struct F_Math_import_int F_Math_import_int;
+struct F_Math_import_int
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* b;
+ Array* x;
+};
+void Math_import_real(void*);
+typedef struct F_Math_import_real F_Math_import_real;
+struct F_Math_import_real
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* b;
+ Array* x;
+};
+void Math_import_real32(void*);
+typedef struct F_Math_import_real32 F_Math_import_real32;
+struct F_Math_import_real32
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* b;
+ Array* x;
+};
+void Math_isnan(void*);
+typedef struct F_Math_isnan F_Math_isnan;
+struct F_Math_isnan
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_j0(void*);
+typedef struct F_Math_j0 F_Math_j0;
+struct F_Math_j0
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_j1(void*);
+typedef struct F_Math_j1 F_Math_j1;
+struct F_Math_j1
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_jn(void*);
+typedef struct F_Math_jn F_Math_jn;
+struct F_Math_jn
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ WORD n;
+ uchar _pad36[4];
+ REAL x;
+};
+void Math_lgamma(void*);
+typedef struct F_Math_lgamma F_Math_lgamma;
+struct F_Math_lgamma
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; uchar _pad4[4]; REAL t1; }* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_log(void*);
+typedef struct F_Math_log F_Math_log;
+struct F_Math_log
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_log10(void*);
+typedef struct F_Math_log10 F_Math_log10;
+struct F_Math_log10
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_log1p(void*);
+typedef struct F_Math_log1p F_Math_log1p;
+struct F_Math_log1p
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_modf(void*);
+typedef struct F_Math_modf F_Math_modf;
+struct F_Math_modf
+{
+ WORD regs[NREG-1];
+ struct{ WORD t0; uchar _pad4[4]; REAL t1; }* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_nextafter(void*);
+typedef struct F_Math_nextafter F_Math_nextafter;
+struct F_Math_nextafter
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_norm1(void*);
+typedef struct F_Math_norm1 F_Math_norm1;
+struct F_Math_norm1
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ Array* x;
+};
+void Math_norm2(void*);
+typedef struct F_Math_norm2 F_Math_norm2;
+struct F_Math_norm2
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ Array* x;
+};
+void Math_pow(void*);
+typedef struct F_Math_pow F_Math_pow;
+struct F_Math_pow
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL y;
+};
+void Math_pow10(void*);
+typedef struct F_Math_pow10 F_Math_pow10;
+struct F_Math_pow10
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ WORD p;
+};
+void Math_realbits32(void*);
+typedef struct F_Math_realbits32 F_Math_realbits32;
+struct F_Math_realbits32
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_realbits64(void*);
+typedef struct F_Math_realbits64 F_Math_realbits64;
+struct F_Math_realbits64
+{
+ WORD regs[NREG-1];
+ LONG* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_remainder(void*);
+typedef struct F_Math_remainder F_Math_remainder;
+struct F_Math_remainder
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ REAL p;
+};
+void Math_rint(void*);
+typedef struct F_Math_rint F_Math_rint;
+struct F_Math_rint
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_scalbn(void*);
+typedef struct F_Math_scalbn F_Math_scalbn;
+struct F_Math_scalbn
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+ WORD n;
+};
+void Math_sin(void*);
+typedef struct F_Math_sin F_Math_sin;
+struct F_Math_sin
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_sinh(void*);
+typedef struct F_Math_sinh F_Math_sinh;
+struct F_Math_sinh
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_sort(void*);
+typedef struct F_Math_sort F_Math_sort;
+struct F_Math_sort
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Array* x;
+ Array* pi;
+};
+void Math_sqrt(void*);
+typedef struct F_Math_sqrt F_Math_sqrt;
+struct F_Math_sqrt
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_tan(void*);
+typedef struct F_Math_tan F_Math_tan;
+struct F_Math_tan
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_tanh(void*);
+typedef struct F_Math_tanh F_Math_tanh;
+struct F_Math_tanh
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_y0(void*);
+typedef struct F_Math_y0 F_Math_y0;
+struct F_Math_y0
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_y1(void*);
+typedef struct F_Math_y1 F_Math_y1;
+struct F_Math_y1
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ REAL x;
+};
+void Math_yn(void*);
+typedef struct F_Math_yn F_Math_yn;
+struct F_Math_yn
+{
+ WORD regs[NREG-1];
+ REAL* ret;
+ uchar temps[12];
+ WORD n;
+ uchar _pad36[4];
+ REAL x;
+};
+#define Math_PATH "$Math"
+#define Math_Infinity Infinity
+#define Math_NaN NaN
+#define Math_MachEps 2.220446049250313e-16
+#define Math_Pi 3.141592653589793
+#define Math_Degree .017453292519943295
+#define Math_INVAL 1
+#define Math_ZDIV 2
+#define Math_OVFL 4
+#define Math_UNFL 8
+#define Math_INEX 16
+#define Math_RND_NR 0
+#define Math_RND_NINF 256
+#define Math_RND_PINF 512
+#define Math_RND_Z 768
+#define Math_RND_MASK 768
+void IPint_add(void*);
+typedef struct F_IPint_add F_IPint_add;
+struct F_IPint_add
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i1;
+ Keyring_IPint* i2;
+};
+void Keyring_aescbc(void*);
+typedef struct F_Keyring_aescbc F_Keyring_aescbc;
+struct F_Keyring_aescbc
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_AESstate* state;
+ Array* buf;
+ WORD n;
+ WORD direction;
+};
+void Keyring_aessetup(void*);
+typedef struct F_Keyring_aessetup F_Keyring_aessetup;
+struct F_Keyring_aessetup
+{
+ WORD regs[NREG-1];
+ Keyring_AESstate** ret;
+ uchar temps[12];
+ Array* key;
+ Array* ivec;
+};
+void Keyring_auth(void*);
+typedef struct F_Keyring_auth F_Keyring_auth;
+struct F_Keyring_auth
+{
+ WORD regs[NREG-1];
+ struct{ String* t0; Array* t1; }* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Keyring_Authinfo* info;
+ WORD setid;
+};
+void IPint_b64toip(void*);
+typedef struct F_IPint_b64toip F_IPint_b64toip;
+struct F_IPint_b64toip
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ String* str;
+};
+void IPint_bebytestoip(void*);
+typedef struct F_IPint_bebytestoip F_IPint_bebytestoip;
+struct F_IPint_bebytestoip
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Array* mag;
+};
+void IPint_bits(void*);
+typedef struct F_IPint_bits F_IPint_bits;
+struct F_IPint_bits
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void IPint_bytestoip(void*);
+typedef struct F_IPint_bytestoip F_IPint_bytestoip;
+struct F_IPint_bytestoip
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Array* buf;
+};
+void Keyring_certtoattr(void*);
+typedef struct F_Keyring_certtoattr F_Keyring_certtoattr;
+struct F_Keyring_certtoattr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_Certificate* c;
+};
+void Keyring_certtostr(void*);
+typedef struct F_Keyring_certtostr F_Keyring_certtostr;
+struct F_Keyring_certtostr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_Certificate* c;
+};
+void IPint_cmp(void*);
+typedef struct F_IPint_cmp F_IPint_cmp;
+struct F_IPint_cmp
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Keyring_IPint* i1;
+ Keyring_IPint* i2;
+};
+void IPint_copy(void*);
+typedef struct F_IPint_copy F_IPint_copy;
+struct F_IPint_copy
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void DigestState_copy(void*);
+typedef struct F_DigestState_copy F_DigestState_copy;
+struct F_DigestState_copy
+{
+ WORD regs[NREG-1];
+ Keyring_DigestState** ret;
+ uchar temps[12];
+ Keyring_DigestState* d;
+};
+void Keyring_descbc(void*);
+typedef struct F_Keyring_descbc F_Keyring_descbc;
+struct F_Keyring_descbc
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_DESstate* state;
+ Array* buf;
+ WORD n;
+ WORD direction;
+};
+void Keyring_desecb(void*);
+typedef struct F_Keyring_desecb F_Keyring_desecb;
+struct F_Keyring_desecb
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_DESstate* state;
+ Array* buf;
+ WORD n;
+ WORD direction;
+};
+void Keyring_dessetup(void*);
+typedef struct F_Keyring_dessetup F_Keyring_dessetup;
+struct F_Keyring_dessetup
+{
+ WORD regs[NREG-1];
+ Keyring_DESstate** ret;
+ uchar temps[12];
+ Array* key;
+ Array* ivec;
+};
+void Keyring_dhparams(void*);
+typedef struct F_Keyring_dhparams F_Keyring_dhparams;
+struct F_Keyring_dhparams
+{
+ WORD regs[NREG-1];
+ struct{ Keyring_IPint* t0; Keyring_IPint* t1; }* ret;
+ uchar temps[12];
+ WORD nbits;
+};
+void IPint_div(void*);
+typedef struct F_IPint_div F_IPint_div;
+struct F_IPint_div
+{
+ WORD regs[NREG-1];
+ struct{ Keyring_IPint* t0; Keyring_IPint* t1; }* ret;
+ uchar temps[12];
+ Keyring_IPint* i1;
+ Keyring_IPint* i2;
+};
+void IPint_eq(void*);
+typedef struct F_IPint_eq F_IPint_eq;
+struct F_IPint_eq
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Keyring_IPint* i1;
+ Keyring_IPint* i2;
+};
+void IPint_expmod(void*);
+typedef struct F_IPint_expmod F_IPint_expmod;
+struct F_IPint_expmod
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* base;
+ Keyring_IPint* exp;
+ Keyring_IPint* mod;
+};
+void Keyring_genSK(void*);
+typedef struct F_Keyring_genSK F_Keyring_genSK;
+struct F_Keyring_genSK
+{
+ WORD regs[NREG-1];
+ Keyring_SK** ret;
+ uchar temps[12];
+ String* algname;
+ String* owner;
+ WORD length;
+};
+void Keyring_genSKfromPK(void*);
+typedef struct F_Keyring_genSKfromPK F_Keyring_genSKfromPK;
+struct F_Keyring_genSKfromPK
+{
+ WORD regs[NREG-1];
+ Keyring_SK** ret;
+ uchar temps[12];
+ Keyring_PK* pk;
+ String* owner;
+};
+void Keyring_getbytearray(void*);
+typedef struct F_Keyring_getbytearray F_Keyring_getbytearray;
+struct F_Keyring_getbytearray
+{
+ WORD regs[NREG-1];
+ struct{ Array* t0; String* t1; }* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Keyring_getmsg(void*);
+typedef struct F_Keyring_getmsg F_Keyring_getmsg;
+struct F_Keyring_getmsg
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Keyring_getstring(void*);
+typedef struct F_Keyring_getstring F_Keyring_getstring;
+struct F_Keyring_getstring
+{
+ WORD regs[NREG-1];
+ struct{ String* t0; String* t1; }* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+};
+void Keyring_hmac_md5(void*);
+typedef struct F_Keyring_hmac_md5 F_Keyring_hmac_md5;
+struct F_Keyring_hmac_md5
+{
+ WORD regs[NREG-1];
+ Keyring_DigestState** ret;
+ uchar temps[12];
+ Array* data;
+ WORD n;
+ Array* key;
+ Array* digest;
+ Keyring_DigestState* state;
+};
+void Keyring_hmac_sha1(void*);
+typedef struct F_Keyring_hmac_sha1 F_Keyring_hmac_sha1;
+struct F_Keyring_hmac_sha1
+{
+ WORD regs[NREG-1];
+ Keyring_DigestState** ret;
+ uchar temps[12];
+ Array* data;
+ WORD n;
+ Array* key;
+ Array* digest;
+ Keyring_DigestState* state;
+};
+void Keyring_ideacbc(void*);
+typedef struct F_Keyring_ideacbc F_Keyring_ideacbc;
+struct F_Keyring_ideacbc
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_IDEAstate* state;
+ Array* buf;
+ WORD n;
+ WORD direction;
+};
+void Keyring_ideaecb(void*);
+typedef struct F_Keyring_ideaecb F_Keyring_ideaecb;
+struct F_Keyring_ideaecb
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_IDEAstate* state;
+ Array* buf;
+ WORD n;
+ WORD direction;
+};
+void Keyring_ideasetup(void*);
+typedef struct F_Keyring_ideasetup F_Keyring_ideasetup;
+struct F_Keyring_ideasetup
+{
+ WORD regs[NREG-1];
+ Keyring_IDEAstate** ret;
+ uchar temps[12];
+ Array* key;
+ Array* ivec;
+};
+void IPint_inttoip(void*);
+typedef struct F_IPint_inttoip F_IPint_inttoip;
+struct F_IPint_inttoip
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ WORD i;
+};
+void IPint_invert(void*);
+typedef struct F_IPint_invert F_IPint_invert;
+struct F_IPint_invert
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* base;
+ Keyring_IPint* mod;
+};
+void IPint_iptob64(void*);
+typedef struct F_IPint_iptob64 F_IPint_iptob64;
+struct F_IPint_iptob64
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void IPint_iptobebytes(void*);
+typedef struct F_IPint_iptobebytes F_IPint_iptobebytes;
+struct F_IPint_iptobebytes
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void IPint_iptobytes(void*);
+typedef struct F_IPint_iptobytes F_IPint_iptobytes;
+struct F_IPint_iptobytes
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void IPint_iptoint(void*);
+typedef struct F_IPint_iptoint F_IPint_iptoint;
+struct F_IPint_iptoint
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void IPint_iptostr(void*);
+typedef struct F_IPint_iptostr F_IPint_iptostr;
+struct F_IPint_iptostr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+ WORD base;
+};
+void Keyring_md4(void*);
+typedef struct F_Keyring_md4 F_Keyring_md4;
+struct F_Keyring_md4
+{
+ WORD regs[NREG-1];
+ Keyring_DigestState** ret;
+ uchar temps[12];
+ Array* buf;
+ WORD n;
+ Array* digest;
+ Keyring_DigestState* state;
+};
+void Keyring_md5(void*);
+typedef struct F_Keyring_md5 F_Keyring_md5;
+struct F_Keyring_md5
+{
+ WORD regs[NREG-1];
+ Keyring_DigestState** ret;
+ uchar temps[12];
+ Array* buf;
+ WORD n;
+ Array* digest;
+ Keyring_DigestState* state;
+};
+void IPint_mul(void*);
+typedef struct F_IPint_mul F_IPint_mul;
+struct F_IPint_mul
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i1;
+ Keyring_IPint* i2;
+};
+void IPint_neg(void*);
+typedef struct F_IPint_neg F_IPint_neg;
+struct F_IPint_neg
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+};
+void Keyring_pktoattr(void*);
+typedef struct F_Keyring_pktoattr F_Keyring_pktoattr;
+struct F_Keyring_pktoattr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_PK* pk;
+};
+void Keyring_pktostr(void*);
+typedef struct F_Keyring_pktostr F_Keyring_pktostr;
+struct F_Keyring_pktostr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_PK* pk;
+};
+void Keyring_putbytearray(void*);
+typedef struct F_Keyring_putbytearray F_Keyring_putbytearray;
+struct F_Keyring_putbytearray
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Array* a;
+ WORD n;
+};
+void Keyring_puterror(void*);
+typedef struct F_Keyring_puterror F_Keyring_puterror;
+struct F_Keyring_puterror
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ String* s;
+};
+void Keyring_putstring(void*);
+typedef struct F_Keyring_putstring F_Keyring_putstring;
+struct F_Keyring_putstring
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ String* s;
+};
+void IPint_random(void*);
+typedef struct F_IPint_random F_IPint_random;
+struct F_IPint_random
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ WORD minbits;
+ WORD maxbits;
+};
+void Keyring_rc4(void*);
+typedef struct F_Keyring_rc4 F_Keyring_rc4;
+struct F_Keyring_rc4
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_RC4state* state;
+ Array* buf;
+ WORD n;
+};
+void Keyring_rc4back(void*);
+typedef struct F_Keyring_rc4back F_Keyring_rc4back;
+struct F_Keyring_rc4back
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_RC4state* state;
+ WORD n;
+};
+void Keyring_rc4setup(void*);
+typedef struct F_Keyring_rc4setup F_Keyring_rc4setup;
+struct F_Keyring_rc4setup
+{
+ WORD regs[NREG-1];
+ Keyring_RC4state** ret;
+ uchar temps[12];
+ Array* seed;
+};
+void Keyring_rc4skip(void*);
+typedef struct F_Keyring_rc4skip F_Keyring_rc4skip;
+struct F_Keyring_rc4skip
+{
+ WORD regs[NREG-1];
+ WORD noret;
+ uchar temps[12];
+ Keyring_RC4state* state;
+ WORD n;
+};
+void Keyring_readauthinfo(void*);
+typedef struct F_Keyring_readauthinfo F_Keyring_readauthinfo;
+struct F_Keyring_readauthinfo
+{
+ WORD regs[NREG-1];
+ Keyring_Authinfo** ret;
+ uchar temps[12];
+ String* filename;
+};
+void Keyring_senderrmsg(void*);
+typedef struct F_Keyring_senderrmsg F_Keyring_senderrmsg;
+struct F_Keyring_senderrmsg
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ String* s;
+};
+void Keyring_sendmsg(void*);
+typedef struct F_Keyring_sendmsg F_Keyring_sendmsg;
+struct F_Keyring_sendmsg
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Sys_FD* fd;
+ Array* buf;
+ WORD n;
+};
+void Keyring_sha1(void*);
+typedef struct F_Keyring_sha1 F_Keyring_sha1;
+struct F_Keyring_sha1
+{
+ WORD regs[NREG-1];
+ Keyring_DigestState** ret;
+ uchar temps[12];
+ Array* buf;
+ WORD n;
+ Array* digest;
+ Keyring_DigestState* state;
+};
+void IPint_shl(void*);
+typedef struct F_IPint_shl F_IPint_shl;
+struct F_IPint_shl
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+ WORD n;
+};
+void IPint_shr(void*);
+typedef struct F_IPint_shr F_IPint_shr;
+struct F_IPint_shr
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i;
+ WORD n;
+};
+void Keyring_sign(void*);
+typedef struct F_Keyring_sign F_Keyring_sign;
+struct F_Keyring_sign
+{
+ WORD regs[NREG-1];
+ Keyring_Certificate** ret;
+ uchar temps[12];
+ Keyring_SK* sk;
+ WORD exp;
+ Keyring_DigestState* state;
+ String* ha;
+};
+void Keyring_signm(void*);
+typedef struct F_Keyring_signm F_Keyring_signm;
+struct F_Keyring_signm
+{
+ WORD regs[NREG-1];
+ Keyring_Certificate** ret;
+ uchar temps[12];
+ Keyring_SK* sk;
+ Keyring_IPint* m;
+ String* ha;
+};
+void Keyring_sktoattr(void*);
+typedef struct F_Keyring_sktoattr F_Keyring_sktoattr;
+struct F_Keyring_sktoattr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_SK* sk;
+};
+void Keyring_sktopk(void*);
+typedef struct F_Keyring_sktopk F_Keyring_sktopk;
+struct F_Keyring_sktopk
+{
+ WORD regs[NREG-1];
+ Keyring_PK** ret;
+ uchar temps[12];
+ Keyring_SK* sk;
+};
+void Keyring_sktostr(void*);
+typedef struct F_Keyring_sktostr F_Keyring_sktostr;
+struct F_Keyring_sktostr
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Keyring_SK* sk;
+};
+void Keyring_strtocert(void*);
+typedef struct F_Keyring_strtocert F_Keyring_strtocert;
+struct F_Keyring_strtocert
+{
+ WORD regs[NREG-1];
+ Keyring_Certificate** ret;
+ uchar temps[12];
+ String* s;
+};
+void IPint_strtoip(void*);
+typedef struct F_IPint_strtoip F_IPint_strtoip;
+struct F_IPint_strtoip
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ String* str;
+ WORD base;
+};
+void Keyring_strtopk(void*);
+typedef struct F_Keyring_strtopk F_Keyring_strtopk;
+struct F_Keyring_strtopk
+{
+ WORD regs[NREG-1];
+ Keyring_PK** ret;
+ uchar temps[12];
+ String* s;
+};
+void Keyring_strtosk(void*);
+typedef struct F_Keyring_strtosk F_Keyring_strtosk;
+struct F_Keyring_strtosk
+{
+ WORD regs[NREG-1];
+ Keyring_SK** ret;
+ uchar temps[12];
+ String* s;
+};
+void IPint_sub(void*);
+typedef struct F_IPint_sub F_IPint_sub;
+struct F_IPint_sub
+{
+ WORD regs[NREG-1];
+ Keyring_IPint** ret;
+ uchar temps[12];
+ Keyring_IPint* i1;
+ Keyring_IPint* i2;
+};
+void Keyring_verify(void*);
+typedef struct F_Keyring_verify F_Keyring_verify;
+struct F_Keyring_verify
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Keyring_PK* pk;
+ Keyring_Certificate* cert;
+ Keyring_DigestState* state;
+};
+void Keyring_verifym(void*);
+typedef struct F_Keyring_verifym F_Keyring_verifym;
+struct F_Keyring_verifym
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Keyring_PK* pk;
+ Keyring_Certificate* cert;
+ Keyring_IPint* m;
+};
+void Keyring_writeauthinfo(void*);
+typedef struct F_Keyring_writeauthinfo F_Keyring_writeauthinfo;
+struct F_Keyring_writeauthinfo
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ String* filename;
+ Keyring_Authinfo* info;
+};
+#define Keyring_PATH "$Keyring"
+#define Keyring_Encrypt 0
+#define Keyring_Decrypt 1
+#define Keyring_AESbsize 16
+#define Keyring_DESbsize 8
+#define Keyring_IDEAbsize 8
+#define Keyring_DEScbc 0
+#define Keyring_DESecb 1
+#define Keyring_SHA1 2
+#define Keyring_MD5 3
+#define Keyring_MD4 4
+#define Keyring_IDEAcbc 5
+#define Keyring_IDEAecb 6
+#define Keyring_SHA1dlen 20
+#define Keyring_MD5dlen 16
+#define Keyring_MD4dlen 16
+void Loader_compile(void*);
+typedef struct F_Loader_compile F_Loader_compile;
+struct F_Loader_compile
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Modlink* mp;
+ WORD flag;
+};
+void Loader_dnew(void*);
+typedef struct F_Loader_dnew F_Loader_dnew;
+struct F_Loader_dnew
+{
+ WORD regs[NREG-1];
+ Loader_Niladt** ret;
+ uchar temps[12];
+ WORD size;
+ Array* map;
+};
+void Loader_ext(void*);
+typedef struct F_Loader_ext F_Loader_ext;
+struct F_Loader_ext
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Modlink* mp;
+ WORD idx;
+ WORD pc;
+ WORD tdesc;
+};
+void Loader_ifetch(void*);
+typedef struct F_Loader_ifetch F_Loader_ifetch;
+struct F_Loader_ifetch
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ Modlink* mp;
+};
+void Loader_link(void*);
+typedef struct F_Loader_link F_Loader_link;
+struct F_Loader_link
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ Modlink* mp;
+};
+void Loader_newmod(void*);
+typedef struct F_Loader_newmod F_Loader_newmod;
+struct F_Loader_newmod
+{
+ WORD regs[NREG-1];
+ Modlink** ret;
+ uchar temps[12];
+ String* name;
+ WORD ss;
+ WORD nlink;
+ Array* inst;
+ Loader_Niladt* data;
+};
+void Loader_tdesc(void*);
+typedef struct F_Loader_tdesc F_Loader_tdesc;
+struct F_Loader_tdesc
+{
+ WORD regs[NREG-1];
+ Array** ret;
+ uchar temps[12];
+ Modlink* mp;
+};
+void Loader_tnew(void*);
+typedef struct F_Loader_tnew F_Loader_tnew;
+struct F_Loader_tnew
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Modlink* mp;
+ WORD size;
+ Array* map;
+};
+#define Loader_PATH "$Loader"
+void Face_haschar(void*);
+typedef struct F_Face_haschar F_Face_haschar;
+struct F_Face_haschar
+{
+ WORD regs[NREG-1];
+ WORD* ret;
+ uchar temps[12];
+ Freetype_Face* face;
+ WORD c;
+};
+void Face_loadglyph(void*);
+typedef struct F_Face_loadglyph F_Face_loadglyph;
+struct F_Face_loadglyph
+{
+ WORD regs[NREG-1];
+ Freetype_Glyph** ret;
+ uchar temps[12];
+ Freetype_Face* face;
+ WORD c;
+};
+void Freetype_newface(void*);
+typedef struct F_Freetype_newface F_Freetype_newface;
+struct F_Freetype_newface
+{
+ WORD regs[NREG-1];
+ Freetype_Face** ret;
+ uchar temps[12];
+ String* path;
+ WORD index;
+};
+void Freetype_newmemface(void*);
+typedef struct F_Freetype_newmemface F_Freetype_newmemface;
+struct F_Freetype_newmemface
+{
+ WORD regs[NREG-1];
+ Freetype_Face** ret;
+ uchar temps[12];
+ Array* data;
+ WORD index;
+};
+void Face_setcharsize(void*);
+typedef struct F_Face_setcharsize F_Face_setcharsize;
+struct F_Face_setcharsize
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Freetype_Face* face;
+ WORD pts;
+ WORD hdpi;
+ WORD vdpi;
+};
+void Face_settransform(void*);
+typedef struct F_Face_settransform F_Face_settransform;
+struct F_Face_settransform
+{
+ WORD regs[NREG-1];
+ String** ret;
+ uchar temps[12];
+ Freetype_Face* face;
+ Freetype_Matrix* m;
+ Freetype_Vector* v;
+};
+#define Freetype_PATH "$Freetype"
+#define Freetype_STYLE_ITALIC 1
+#define Freetype_STYLE_BOLD 2
+#pragma pack off
+#pragma hjdicks off
diff --git a/libinterp/sign.c b/libinterp/sign.c
new file mode 100644
index 00000000..950ad300
--- /dev/null
+++ b/libinterp/sign.c
@@ -0,0 +1,29 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include <kernel.h>
+
+/*
+ * these stubs are used when devsign isn't configured
+ */
+
+int
+verifysigner(uchar *sign, int len, uchar *data, ulong ndata)
+{
+ USED(sign);
+ USED(len);
+ USED(data);
+ USED(ndata);
+
+ return 1;
+}
+
+int
+mustbesigned(char *path, uchar *code, ulong length, Dir *dir)
+{
+ USED(path);
+ USED(code);
+ USED(length);
+ USED(dir);
+ return 0;
+}
diff --git a/libinterp/stack.c b/libinterp/stack.c
new file mode 100644
index 00000000..037d1b49
--- /dev/null
+++ b/libinterp/stack.c
@@ -0,0 +1,118 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <pool.h>
+
+#define T(r) *((void**)(R.r))
+
+void
+newstack(Prog *p)
+{
+ int l;
+ Type *t;
+ Frame *f;
+ Stkext *ns;
+
+ f = T(s);
+
+ t = f->t;
+ if(t == nil)
+ t = SEXTYPE(f)->reg.TR;
+
+ f->lr = nil;
+ f->mr = nil;
+ f->fp = nil;
+ l = p->R.M->m->ss;
+ /* 16 bytes for Stkext record keeping */
+ if(l < t->size+16)
+ l = t->size+16;
+ ns = mallocz(l, 0);
+ if(ns == nil)
+ error(exNomem);
+
+ ns->reg.TR = t;
+ ns->reg.SP = nil;
+ ns->reg.TS = nil;
+ ns->reg.EX = nil;
+ p->R.EX = ns->stack;
+ p->R.TS = ns->stack + l;
+ p->R.SP = ns->reg.tos.fu + t->size;
+ p->R.FP = ns->reg.tos.fu;
+
+ memmove(p->R.FP, f, t->size);
+ f = (Frame*)p->R.FP;
+ f->t = nil;
+}
+
+void
+extend(void)
+{
+ int l;
+ Type *t;
+ Frame *f;
+ Stkext *ns;
+
+ t = R.s;
+ l = R.M->m->ss;
+ /* 16 bytes for Stkext record keeping */
+ if(l < t->size+16)
+ l = 2*t->size+16;
+ ns = mallocz(l, 0);
+ if(ns == nil)
+ error(exNomem);
+
+ ns->reg.TR = t;
+ ns->reg.SP = R.SP;
+ ns->reg.TS = R.TS;
+ ns->reg.EX = R.EX;
+ f = ns->reg.tos.fr;
+ f->t = nil;
+ f->mr = nil;
+ R.s = f;
+ R.EX = ns->stack;
+ R.TS = ns->stack + l;
+ R.SP = ns->reg.tos.fu + t->size;
+
+ if (t->np)
+ initmem(t, f);
+}
+
+void
+unextend(Frame *f)
+{
+ Stkext *sx;
+ Type *t;
+
+ sx = SEXTYPE(f);
+ R.SP = sx->reg.SP;
+ R.TS = sx->reg.TS;
+ R.EX = sx->reg.EX;
+ t = sx->reg.TR;
+ if (t->np)
+ freeptrs(f, t);
+ free(sx);
+}
+
+void
+unframe(void)
+{
+ Type *t;
+ Frame *f;
+ Stkext *sx;
+
+ f = (Frame*)R.FP;
+ t = f->t;
+ if(t == nil)
+ t = SEXTYPE(f)->reg.TR;
+
+ R.SP = R.FP+t->size;
+
+ f = T(s);
+ if(f->t == nil) {
+ sx = SEXTYPE(f);
+ R.TS = sx->reg.TS;
+ R.EX = sx->reg.EX;
+ free(sx);
+ }
+}
diff --git a/libinterp/string.c b/libinterp/string.c
new file mode 100644
index 00000000..4a4eb54e
--- /dev/null
+++ b/libinterp/string.c
@@ -0,0 +1,612 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+#define OP(fn) void fn(void)
+#define B(r) *((BYTE*)(R.r))
+#define W(r) *((WORD*)(R.r))
+#define F(r) *((REAL*)(R.r))
+#define V(r) *((LONG*)(R.r))
+#define S(r) *((String**)(R.r))
+#define A(r) *((Array**)(R.r))
+#define L(r) *((List**)(R.r))
+#define P(r) *((WORD**)(R.r))
+#define C(r) *((Channel**)(R.r))
+#define T(r) *((void**)(R.r))
+
+OP(indc)
+{
+ int l;
+ ulong v;
+ String *ss;
+
+ v = W(m);
+ ss = S(s);
+
+ if(ss == H)
+ error(exNilref);
+
+ l = ss->len;
+ if(l < 0) {
+ if(v >= -l)
+e: error(exBounds);
+ l = ss->Srune[v];
+ }
+ else {
+ if(v >= l)
+ goto e;
+ l = ss->Sascii[v];
+ }
+ W(d) = l;
+}
+
+OP(insc)
+{
+ ulong v;
+ int l, r, expand;
+ String *ss, *ns, **sp;
+
+ r = W(s);
+ v = W(m);
+ ss = S(d);
+
+ expand = r >= Runeself;
+
+ if(ss == H) {
+ ss = newstring(0);
+ if(expand) {
+ l = 0;
+ ss->max /= sizeof(Rune);
+ goto r;
+ }
+ }
+ else
+ if(D2H(ss)->ref > 1 || (expand && ss->len > 0))
+ ss = splitc(R.d, expand);
+
+ l = ss->len;
+ if(l < 0 || expand) {
+ l = -l;
+r:
+ if(v < l)
+ ss->Srune[v] = r;
+ else
+ if(v == l && v < ss->max) {
+ ss->len = -(v+1);
+ ss->Srune[v] = r;
+ }
+ else {
+ if(v != l)
+ error(exBounds);
+ ns = newstring((v + 1 + v/4)*sizeof(Rune));
+ memmove(ns->Srune, ss->Srune, -ss->len*sizeof(Rune));
+ ns->Srune[v] = r;
+ ns->len = -(v+1);
+ ns->max /= sizeof(Rune);
+ ss = ns;
+ }
+ }
+ else {
+ if(v < l)
+ ss->Sascii[v] = r;
+ else
+ if(v == l && v < ss->max) {
+ ss->len = v+1;
+ ss->Sascii[v] = r;
+ }
+ else {
+ if(v != l)
+ error(exBounds);
+ ns = newstring(v + 1 + v/4);
+ memmove(ns->Sascii, ss->Sascii, l);
+ ns->Sascii[v] = r;
+ ns->len = v+1;
+ ss = ns;
+ }
+ }
+ if(ss != S(d)) {
+ sp = R.d;
+ destroy(*sp);
+ *sp = ss;
+ }
+}
+
+String*
+slicer(ulong start, ulong v, String *ds)
+{
+ String *ns;
+ int l, nc;
+
+ if(ds == H) {
+ if(start == 0 && v == 0)
+ return H;
+
+ error(exBounds);
+ }
+
+ nc = v - start;
+ if(ds->len < 0) {
+ l = -ds->len;
+ if(v < start || v > l)
+ error(exBounds);
+ ns = newrunes(nc);
+ memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune));
+ }
+ else {
+ l = ds->len;
+ if(v < start || v > l)
+ error(exBounds);
+ ns = newstring(nc);
+ memmove(ns->Sascii, &ds->Sascii[start], nc);
+ }
+
+ return ns;
+}
+
+OP(slicec)
+{
+ String *ns, **sp;
+
+ ns = slicer(W(s), W(m), S(d));
+ sp = R.d;
+ destroy(*sp);
+ *sp = ns;
+}
+
+void
+cvtup(Rune *r, String *s)
+{
+ uchar *bp, *ep;
+
+ bp = (uchar*)s->Sascii;
+ ep = bp + s->len;
+ while(bp < ep)
+ *r++ = *bp++;
+}
+
+String*
+addstring(String *s1, String *s2, int append)
+{
+ Rune *r;
+ String *ns;
+ int l, l1, l2;
+
+ if(s1 == H) {
+ if(s2 == H)
+ return H;
+ return stringdup(s2);
+ }
+ if(D2H(s1)->ref > 1)
+ append = 0;
+ if(s2 == H) {
+ if(append)
+ return s1;
+ return stringdup(s1);
+ }
+
+ if(s1->len < 0) {
+ l1 = -s1->len;
+ if(s2->len < 0)
+ l = l1 - s2->len;
+ else
+ l = l1 + s2->len;
+ if(append && l <= s1->max)
+ ns = s1;
+ else {
+ ns = newrunes(append? (l+l/4): l);
+ memmove(ns->Srune, s1->Srune, l1*sizeof(Rune));
+ }
+ ns->len = -l;
+ r = &ns->Srune[l1];
+ if(s2->len < 0)
+ memmove(r, s2->Srune, -s2->len*sizeof(Rune));
+ else
+ cvtup(r, s2);
+
+ return ns;
+ }
+
+ if(s2->len < 0) {
+ l2 = -s2->len;
+ l = s1->len + l2;
+ ns = newrunes(append? (l+l/4): l);
+ ns->len = -l;
+ cvtup(ns->Srune, s1);
+ memmove(&ns->Srune[s1->len], s2->Srune, l2*sizeof(Rune));
+ return ns;
+ }
+
+ l1 = s1->len;
+ l = l1 + s2->len;
+ if(append && l <= s1->max)
+ ns = s1;
+ else {
+ ns = newstring(append? (l+l/4): l);
+ memmove(ns->Sascii, s1->Sascii, l1);
+ }
+ ns->len = l;
+ memmove(ns->Sascii+l1, s2->Sascii, s2->len);
+
+ return ns;
+}
+
+OP(addc)
+{
+ String *ns, **sp;
+
+ ns = addstring(S(m), S(s), R.m == R.d);
+
+ sp = R.d;
+ if(ns != *sp) {
+ destroy(*sp);
+ *sp = ns;
+ }
+}
+
+OP(cvtca)
+{
+ int l;
+ Rune *r;
+ char *p;
+ String *ss;
+ Array *a, **ap;
+
+ ss = S(s);
+ if(ss == H) {
+ a = mem2array(nil, 0);
+ goto r;
+ }
+ if(ss->len < 0) {
+ l = -ss->len;
+ a = mem2array(nil, runenlen(ss->Srune, l));
+ p = (char*)a->data;
+ r = ss->Srune;
+ while(l--)
+ p += runetochar(p, r++);
+ goto r;
+ }
+ a = mem2array(ss->Sascii, ss->len);
+
+r: ap = R.d;
+ destroy(*ap);
+ *ap = a;
+}
+
+OP(cvtac)
+{
+ Array *a;
+ String *ds, **dp;
+
+ ds = H;
+ a = A(s);
+ if(a != H)
+ ds = c2string((char*)a->data, a->len);
+
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+OP(lenc)
+{
+ int l;
+ String *ss;
+
+ l = 0;
+ ss = S(s);
+ if(ss != H) {
+ l = ss->len;
+ if(l < 0)
+ l = -l;
+ }
+ W(d) = l;
+}
+
+OP(cvtcw)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ W(d) = 0;
+ else
+ if(s->len < 0)
+ W(d) = strtol(string2c(s), nil, 10);
+ else {
+ s->Sascii[s->len] = '\0';
+ W(d) = strtol(s->Sascii, nil, 10);
+ }
+}
+
+OP(cvtcf)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ F(d) = 0.0;
+ else
+ if(s->len < 0)
+ F(d) = strtod(string2c(s), nil);
+ else {
+ s->Sascii[s->len] = '\0';
+ F(d) = strtod(s->Sascii, nil);
+ }
+}
+
+OP(cvtwc)
+{
+ String *ds, **dp;
+
+ ds = newstring(16);
+ ds->len = sprint(ds->Sascii, "%d", W(s));
+
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+OP(cvtlc)
+{
+ String *ds, **dp;
+
+ ds = newstring(16);
+ ds->len = sprint(ds->Sascii, "%lld", V(s));
+
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+OP(cvtfc)
+{
+ String *ds, **dp;
+
+ ds = newstring(32);
+ ds->len = sprint(ds->Sascii, "%g", F(s));
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+char*
+string2c(String *s)
+{
+ char *p;
+ int c, l, nc;
+ Rune *r, *er;
+
+ if(s == H)
+ return "";
+
+ if(s->len >= 0) {
+ s->Sascii[s->len] = '\0';
+ return s->Sascii;
+ }
+
+ nc = -s->len;
+ l = (nc * UTFmax) + UTFmax;
+ if(s->tmp == nil || msize(s->tmp) < l) {
+ free(s->tmp);
+ s->tmp = malloc(l);
+ if(s->tmp == nil)
+ error(exNomem);
+ }
+
+ p = s->tmp;
+ r = s->Srune;
+ er = r + nc;
+ while(r < er) {
+ c = *r++;
+ if(c < Runeself)
+ *p++ = c;
+ else
+ p += runetochar(p, r-1);
+ }
+
+ *p = 0;
+
+ return s->tmp;
+}
+
+String*
+c2string(char *cs, int len)
+{
+ uchar *p;
+ char *ecs;
+ String *s;
+ Rune *r, junk;
+ int c, nc, isrune;
+
+ isrune = 0;
+ ecs = cs+len;
+ p = (uchar*)cs;
+ while(len--) {
+ c = *p++;
+ if(c >= Runeself) {
+ isrune = 1;
+ break;
+ }
+ }
+
+ if(isrune == 0) {
+ nc = ecs - cs;
+ s = newstring(nc);
+ memmove(s->Sascii, cs, nc);
+ return s;
+ }
+
+ p--;
+ nc = p - (uchar*)cs;
+ while(p < (uchar*)ecs) {
+ c = *p;
+ if(c < Runeself)
+ p++;
+ else if(p+UTFmax<=(uchar*)ecs || fullrune((char*)p, (uchar*)ecs-p))
+ p += chartorune(&junk, (char*)p);
+ else
+ break;
+ nc++;
+ }
+ s = newrunes(nc);
+ r = s->Srune;
+ while(nc--)
+ cs += chartorune(r++, cs);
+
+ return s;
+}
+
+String*
+newstring(int nb)
+{
+ Heap *h;
+ String *s;
+
+ h = nheap(sizeof(String)+nb);
+ h->t = &Tstring;
+ Tstring.ref++;
+ s = H2D(String*, h);
+ s->tmp = nil;
+ s->len = nb;
+ s->max = hmsize(h) - (sizeof(String)+sizeof(Heap));
+ return s;
+}
+
+String*
+newrunes(int nr)
+{
+ Heap *h;
+ String *s;
+
+ if(nr == 0)
+ return newstring(nr);
+ if(nr < 0)
+ nr = -nr;
+ h = nheap(sizeof(String)+nr*sizeof(Rune));
+ h->t = &Tstring;
+ Tstring.ref++;
+ s = H2D(String*, h);
+ s->tmp = nil;
+ s->len = -nr;
+ s->max = (hmsize(h) - (sizeof(String)+sizeof(Heap)))/sizeof(Rune);
+ return s;
+}
+
+String*
+stringdup(String *s)
+{
+ String *ns;
+
+ if(s == H)
+ return H;
+
+ if(s->len >= 0) {
+ ns = newstring(s->len);
+ memmove(ns->Sascii, s->Sascii, s->len);
+ return ns;
+ }
+
+ ns = newrunes(-s->len);
+ memmove(ns->Srune, s->Srune,-s->len*sizeof(Rune));
+
+ return ns;
+}
+
+int
+stringcmp(String *s1, String *s2)
+{
+ Rune *r1, *r2;
+ char *a1, *a2;
+ int v, n, n1, n2, c1, c2;
+ static String snil = { 0, 0, nil };
+
+ if(s1 == H)
+ s1 = &snil;
+ if(s2 == H)
+ s2 = &snil;
+
+ if(s1 == s2)
+ return 0;
+
+ v = 0;
+ n1 = s1->len;
+ if(n1 < 0) {
+ n1 = -n1;
+ v |= 1;
+ }
+ n2 = s2->len;
+ if(n2 < 0) {
+ n2 = -n2;
+ v |= 2;
+ }
+
+ n = n1;
+ if(n2 < n)
+ n = n2;
+
+ switch(v) {
+ case 0: /* Ascii Ascii */
+ n = memcmp(s1->Sascii, s2->Sascii, n);
+ if(n == 0)
+ n = n1 - n2;
+ return n;
+ case 1: /* Rune Ascii */
+ r1 = s1->Srune;
+ a2 = s2->Sascii;
+ while(n > 0) {
+ c1 = *r1++;
+ c2 = *a2++;
+ if(c1 != c2)
+ goto ne;
+ n--;
+ }
+ break;
+ case 2: /* Ascii Rune */
+ a1 = s1->Sascii;
+ r2 = s2->Srune;
+ while(n > 0) {
+ c1 = *a1++;
+ c2 = *r2++;
+ if(c1 != c2)
+ goto ne;
+ n--;
+ }
+ break;
+ case 3: /* Rune Rune */
+ r1 = s1->Srune;
+ r2 = s2->Srune;
+ while(n > 0) {
+ c1 = *r1++;
+ c2 = *r2++;
+ if(c1 != c2)
+ goto ne;
+ n--;
+ }
+ break;
+ }
+ return n1 - n2;
+
+ne: if(c1 < c2)
+ return -1;
+ return 1;
+}
+
+String*
+splitc(String **s, int expand)
+{
+ String *ss, *ns;
+
+ ss = *s;
+ if(expand && ss->len > 0) {
+ ns = newrunes(ss->len);
+ cvtup(ns->Srune, ss);
+ }
+ else
+ ns = stringdup(ss);
+
+ destroy(ss);
+ *s = ns;
+ return ns;
+}
diff --git a/libinterp/sysmod.h b/libinterp/sysmod.h
new file mode 100644
index 00000000..5c352ae6
--- /dev/null
+++ b/libinterp/sysmod.h
@@ -0,0 +1,47 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Sysmodtab[]={
+ "announce",0xb7c4ac0,Sys_announce,40,2,{0x0,0x80,},
+ "aprint",0x77442d46,Sys_aprint,0,0,{0},
+ "bind",0x66326d91,Sys_bind,48,2,{0x0,0xc0,},
+ "byte2char",0x3d6094f9,Sys_byte2char,40,2,{0x0,0x80,},
+ "char2byte",0x2ba5ab41,Sys_char2byte,48,2,{0x0,0x40,},
+ "chdir",0xc6935858,Sys_chdir,40,2,{0x0,0x80,},
+ "create",0x54db77d9,Sys_create,48,2,{0x0,0x80,},
+ "dial",0x29e90174,Sys_dial,40,2,{0x0,0xc0,},
+ "dirread",0x72210d71,Sys_dirread,40,2,{0x0,0x80,},
+ "dup",0x6584767b,Sys_dup,40,0,{0},
+ "export",0x6fc6dc03,Sys_export,48,2,{0x0,0xc0,},
+ "fauth",0x20ccc34b,Sys_fauth,40,2,{0x0,0xc0,},
+ "fd2path",0x749c6042,Sys_fd2path,40,2,{0x0,0x80,},
+ "fildes",0x1478f993,Sys_fildes,40,0,{0},
+ "file2chan",0x9f34d686,Sys_file2chan,40,2,{0x0,0xc0,},
+ "fprint",0xf46486c8,Sys_fprint,0,0,{0},
+ "fstat",0xda4499c2,Sys_fstat,40,2,{0x0,0x80,},
+ "fversion",0xfe9c0a06,Sys_fversion,48,2,{0x0,0xa0,},
+ "fwstat",0x50a6c7e0,Sys_fwstat,104,2,{0x0,0xbc,},
+ "iounit",0x5583b730,Sys_iounit,40,2,{0x0,0x80,},
+ "listen",0xb97416e0,Sys_listen,48,2,{0x0,0xe0,},
+ "millisec",0x616977e8,Sys_millisec,32,0,{0},
+ "mount",0x74c17b3a,Sys_mount,56,2,{0x0,0xe8,},
+ "open",0x8f477f99,Sys_open,40,2,{0x0,0x80,},
+ "pctl",0x5df27fb,Sys_pctl,40,2,{0x0,0x40,},
+ "pipe",0x1f2c52ea,Sys_pipe,40,2,{0x0,0x80,},
+ "pread",0x9d8aac6,Sys_pread,56,2,{0x0,0xc0,},
+ "print",0xac849033,Sys_print,0,0,{0},
+ "pwrite",0x9d8aac6,Sys_pwrite,56,2,{0x0,0xc0,},
+ "read",0x7cfef557,Sys_read,48,2,{0x0,0xc0,},
+ "remove",0xc6935858,Sys_remove,40,2,{0x0,0x80,},
+ "seek",0xaeccaddb,Sys_seek,56,2,{0x0,0x80,},
+ "sleep",0xe67bf126,Sys_sleep,40,0,{0},
+ "sprint",0x4c0624b6,Sys_sprint,0,0,{0},
+ "stat",0x319328dd,Sys_stat,40,2,{0x0,0x80,},
+ "stream",0xb9e8f9ea,Sys_stream,48,2,{0x0,0xc0,},
+ "tokenize",0x57338f20,Sys_tokenize,40,2,{0x0,0xc0,},
+ "unmount",0x21e337e3,Sys_unmount,40,2,{0x0,0xc0,},
+ "utfbytes",0x1d4a1f4,Sys_utfbytes,40,2,{0x0,0x80,},
+ "werrstr",0xc6935858,Sys_werrstr,40,2,{0x0,0x80,},
+ "write",0x7cfef557,Sys_write,48,2,{0x0,0xc0,},
+ "wstat",0x56b02096,Sys_wstat,104,2,{0x0,0xbc,},
+ 0
+};
+#define Sysmodlen 42
diff --git a/libinterp/tab.h b/libinterp/tab.h
new file mode 100644
index 00000000..bc9dda1c
--- /dev/null
+++ b/libinterp/tab.h
@@ -0,0 +1,184 @@
+struct
+{
+ char* name;
+ int op;
+ int terminal;
+}keywds[] =
+{
+ "nop", INOP, TOKI0,
+ "alt", IALT, TOKI3,
+ "nbalt", INBALT, TOKI3,
+ "goto", IGOTO, TOKI2,
+ "call", ICALL, TOKI2,
+ "frame", IFRAME, TOKI2,
+ "spawn", ISPAWN, TOKI2,
+ "runt", IRUNT, TOKI2,
+ "load", ILOAD, TOKI3,
+ "mcall", IMCALL, TOKI3,
+ "mspawn", IMSPAWN, TOKI3,
+ "mframe", IMFRAME, TOKI3,
+ "ret", IRET, TOKI0,
+ "jmp", IJMP, TOKI1,
+ "case", ICASE, TOKI2,
+ "exit", IEXIT, TOKI0,
+ "new", INEW, TOKI2,
+ "newa", INEWA, TOKI3,
+ "newcb", INEWCB, TOKI1,
+ "newcw", INEWCW, TOKI1,
+ "newcf", INEWCF, TOKI1,
+ "newcp", INEWCP, TOKI1,
+ "newcm", INEWCM, TOKI2,
+ "newcmp", INEWCMP, TOKI2,
+ "send", ISEND, TOKI2,
+ "recv", IRECV, TOKI2,
+ "consb", ICONSB, TOKI2,
+ "consw", ICONSW, TOKI2,
+ "consp", ICONSP, TOKI2,
+ "consf", ICONSF, TOKI2,
+ "consm", ICONSM, TOKI3,
+ "consmp", ICONSMP, TOKI3,
+ "headb", IHEADB, TOKI2,
+ "headw", IHEADW, TOKI2,
+ "headp", IHEADP, TOKI2,
+ "headf", IHEADF, TOKI2,
+ "headm", IHEADM, TOKI3,
+ "headmp", IHEADMP, TOKI3,
+ "tail", ITAIL, TOKI2,
+ "lea", ILEA, TOKI2,
+ "indx", IINDX, TOKI3,
+ "movp", IMOVP, TOKI2,
+ "movm", IMOVM, TOKI3,
+ "movmp", IMOVMP, TOKI3,
+ "movb", IMOVB, TOKI2,
+ "movw", IMOVW, TOKI2,
+ "movf", IMOVF, TOKI2,
+ "cvtbw", ICVTBW, TOKI2,
+ "cvtwb", ICVTWB, TOKI2,
+ "cvtfw", ICVTFW, TOKI2,
+ "cvtwf", ICVTWF, TOKI2,
+ "cvtca", ICVTCA, TOKI2,
+ "cvtac", ICVTAC, TOKI2,
+ "cvtwc", ICVTWC, TOKI2,
+ "cvtcw", ICVTCW, TOKI2,
+ "cvtfc", ICVTFC, TOKI2,
+ "cvtcf", ICVTCF, TOKI2,
+ "addb", IADDB, TOKI3,
+ "addw", IADDW, TOKI3,
+ "addf", IADDF, TOKI3,
+ "subb", ISUBB, TOKI3,
+ "subw", ISUBW, TOKI3,
+ "subf", ISUBF, TOKI3,
+ "mulb", IMULB, TOKI3,
+ "mulw", IMULW, TOKI3,
+ "mulf", IMULF, TOKI3,
+ "divb", IDIVB, TOKI3,
+ "divw", IDIVW, TOKI3,
+ "divf", IDIVF, TOKI3,
+ "modw", IMODW, TOKI3,
+ "modb", IMODB, TOKI3,
+ "andb", IANDB, TOKI3,
+ "andw", IANDW, TOKI3,
+ "orb", IORB, TOKI3,
+ "orw", IORW, TOKI3,
+ "xorb", IXORB, TOKI3,
+ "xorw", IXORW, TOKI3,
+ "shlb", ISHLB, TOKI3,
+ "shlw", ISHLW, TOKI3,
+ "shrb", ISHRB, TOKI3,
+ "shrw", ISHRW, TOKI3,
+ "insc", IINSC, TOKI3,
+ "indc", IINDC, TOKI3,
+ "addc", IADDC, TOKI3,
+ "lenc", ILENC, TOKI2,
+ "lena", ILENA, TOKI2,
+ "lenl", ILENL, TOKI2,
+ "beqb", IBEQB, TOKI3,
+ "bneb", IBNEB, TOKI3,
+ "bltb", IBLTB, TOKI3,
+ "bleb", IBLEB, TOKI3,
+ "bgtb", IBGTB, TOKI3,
+ "bgeb", IBGEB, TOKI3,
+ "beqw", IBEQW, TOKI3,
+ "bnew", IBNEW, TOKI3,
+ "bltw", IBLTW, TOKI3,
+ "blew", IBLEW, TOKI3,
+ "bgtw", IBGTW, TOKI3,
+ "bgew", IBGEW, TOKI3,
+ "beqf", IBEQF, TOKI3,
+ "bnef", IBNEF, TOKI3,
+ "bltf", IBLTF, TOKI3,
+ "blef", IBLEF, TOKI3,
+ "bgtf", IBGTF, TOKI3,
+ "bgef", IBGEF, TOKI3,
+ "beqc", IBEQC, TOKI3,
+ "bnec", IBNEC, TOKI3,
+ "bltc", IBLTC, TOKI3,
+ "blec", IBLEC, TOKI3,
+ "bgtc", IBGTC, TOKI3,
+ "bgec", IBGEC, TOKI3,
+ "slicea", ISLICEA, TOKI3,
+ "slicela", ISLICELA, TOKI3,
+ "slicec", ISLICEC, TOKI3,
+ "indw", IINDW, TOKI3,
+ "indf", IINDF, TOKI3,
+ "indb", IINDB, TOKI3,
+ "negf", INEGF, TOKI2,
+ "movl", IMOVL, TOKI2,
+ "addl", IADDL, TOKI3,
+ "subl", ISUBL, TOKI3,
+ "divl", IDIVL, TOKI3,
+ "modl", IMODL, TOKI3,
+ "mull", IMULL, TOKI3,
+ "andl", IANDL, TOKI3,
+ "orl", IORL, TOKI3,
+ "xorl", IXORL, TOKI3,
+ "shll", ISHLL, TOKI3,
+ "shrl", ISHRL, TOKI3,
+ "bnel", IBNEL, TOKI3,
+ "bltl", IBLTL, TOKI3,
+ "blel", IBLEL, TOKI3,
+ "bgtl", IBGTL, TOKI3,
+ "bgel", IBGEL, TOKI3,
+ "beql", IBEQL, TOKI3,
+ "cvtlf", ICVTLF, TOKI2,
+ "cvtfl", ICVTFL, TOKI2,
+ "cvtlw", ICVTLW, TOKI2,
+ "cvtwl", ICVTWL, TOKI2,
+ "cvtlc", ICVTLC, TOKI2,
+ "cvtcl", ICVTCL, TOKI2,
+ "headl", IHEADL, TOKI2,
+ "consl", ICONSL, TOKI2,
+ "newcl", INEWCL, TOKI1,
+ "casec", ICASEC, TOKI2,
+ "indl", IINDL, TOKI3,
+ "movpc", IMOVPC, TOKI2,
+ "tcmp", ITCMP, TOKI2,
+ "mnewz", IMNEWZ, TOKI3,
+ "cvtrf", ICVTRF, TOKI2,
+ "cvtfr", ICVTFR, TOKI2,
+ "cvtws", ICVTWS, TOKI2,
+ "cvtsw", ICVTSW, TOKI2,
+ "lsrw", ILSRW, TOKI3,
+ "lsrl", ILSRL, TOKI3,
+ "eclr", IECLR, TOKI0,
+ "newz", INEWZ, TOKI2,
+ "newaz", INEWAZ, TOKI3,
+ "raise", IRAISE, TOKI1,
+ "casel", ICASEL, TOKI2,
+ "mulx", IMULX, TOKI3,
+ "divx", IDIVX, TOKI3,
+ "cvtxx", ICVTXX, TOKI3,
+ "mulx0", IMULX0, TOKI3,
+ "divx0", IDIVX0, TOKI3,
+ "cvtxx0", ICVTXX0, TOKI3,
+ "mulx1", IMULX1, TOKI3,
+ "divx1", IDIVX1, TOKI3,
+ "cvtxx1", ICVTXX1, TOKI3,
+ "cvtfx", ICVTFX, TOKI3,
+ "cvtxf", ICVTXF, TOKI3,
+ "expw", IEXPW, TOKI3,
+ "expl", IEXPL, TOKI3,
+ "expf", IEXPF, TOKI3,
+ "self", ISELF, TOKI1,
+ 0,
+};
diff --git a/libinterp/tk.c b/libinterp/tk.c
new file mode 100644
index 00000000..2556a224
--- /dev/null
+++ b/libinterp/tk.c
@@ -0,0 +1,1295 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "draw.h"
+#include "tk.h"
+#include "tkmod.h"
+#include "pool.h"
+#include "drawif.h"
+#include "keyboard.h"
+#include "raise.h"
+#include "kernel.h"
+
+extern void tkfreetop(Heap*, int);
+Type* fakeTkTop;
+static uchar TktypeMap[] = Tk_Toplevel_map;
+int tkstylus;
+void (*tkwiretap)(void*, char*, char*, void*, Rectangle*);
+
+static void tktopimagedptr(TkTop*, Draw_Image*);
+static char*tkputwinimage(Tk*, Draw_Image*, int);
+
+static void
+lockctxt(TkCtxt *ctxt)
+{
+ libqlock(ctxt->lock);
+}
+
+static void
+unlockctxt(TkCtxt *ctxt)
+{
+ libqunlock(ctxt->lock);
+}
+
+static void
+tkmarktop(Type *t, void *vw)
+{
+ Heap *h;
+ TkVar *v;
+ TkPanelimage *di;
+ TkTop *top;
+ Tk *w, *next;
+ TkWin *tkw;
+
+ markheap(t, vw);
+ top = vw;
+ // XXX do we need to lock context here??
+ for(v = top->vars; v; v = v->link) {
+ if(v->type == TkVchan) {
+ h = D2H(v->value);
+ Setmark(h);
+ }
+ }
+ for (di = top->panelimages; di != nil; di = di->link) {
+ h = D2H(di->image);
+ Setmark(h);
+ }
+ for(w = top->windows; w != nil; w = next){
+ tkw = TKobj(TkWin, w);
+ if(tkw->image != nil){
+ h = D2H(tkw->di);
+ Setmark(h);
+ }
+ next = tkw->next;
+ }
+}
+
+void
+tkmodinit(void)
+{
+ builtinmod("$Tk", Tkmodtab, Tkmodlen);
+ fmtinstall('v', tkeventfmt); /* XXX */
+
+ fakeTkTop = dtype(tkfreetop, sizeof(TkTop), TktypeMap, sizeof(TktypeMap));
+ fakeTkTop->mark = tkmarktop;
+
+ tksorttable();
+}
+
+void
+Tk_toplevel(void *a)
+{
+ Tk *tk;
+ Heap *h;
+ TkTop *t;
+ TkWin *tkw;
+ TkCtxt *ctxt;
+ Display *disp;
+ F_Tk_toplevel *f = a;
+ void *r;
+
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ disp = checkdisplay(f->d);
+
+ h = heapz(fakeTkTop);
+ t = H2D(TkTop*, h);
+ poolimmutable(h);
+
+ t->dd = f->d;
+ D2H(t->dd)->ref++;
+
+ t->execdepth = -1;
+ t->display = disp;
+
+ tk = tknewobj(t, TKframe, sizeof(Tk)+sizeof(TkWin));
+ if(tk == nil) {
+ destroy(t);
+ return;
+ }
+
+ tk->act.x = 0;
+ tk->act.y = 0;
+ tk->act.width = 1; /* XXX why not zero? */
+ tk->act.height = 1;
+ tk->flag |= Tkwindow;
+
+ tkw = TKobj(TkWin, tk);
+ tkw->di = H;
+
+ tktopopt(tk, string2c(f->arg));
+
+ tk->geom = tkmoveresize;
+ tk->name = tkmkname(".");
+ if(tk->name == nil) {
+ tkfreeobj(tk);
+ destroy(t);
+ return;
+ }
+
+ ctxt = tknewctxt(disp);
+ if(ctxt == nil) {
+ tkfreeobj(tk);
+ destroy(t);
+ return;
+ }
+ t->ctxt = ctxt;
+ t->screenr = disp->image->r;
+
+ tkw->next = t->windows;
+ t->windows = tk;
+ t->root = tk;
+ Setmark(h);
+ poolmutable(h);
+ t->wreq = cnewc(&Tptr, movp, 8);
+ *f->ret = (Tk_Toplevel*)t;
+}
+
+void
+Tk_cmd(void *a)
+{
+ TkTop *t;
+ char *val, *e;
+ F_Tk_cmd *f = a;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, f->ret);
+ return;
+ }
+ lockctxt(t->ctxt);
+ val = nil;
+ e = tkexec(t, string2c(f->arg), &val);
+ unlockctxt(t->ctxt);
+ if(e == TkNomem){
+ free(val);
+ error(exNomem); /* what about f->ret? */
+ }
+ if(e != nil && t->errx[0] != '\0'){
+ char *s = tkerrstr(t, e);
+
+ retstr(s, f->ret);
+ free(s);
+ }
+ else
+ retstr(e == nil ? val : e, f->ret);
+ if(tkwiretap != nil)
+ tkwiretap(t, string2c(f->arg), val, nil, nil);
+ free(val);
+}
+
+void
+Tk_color(void *fp)
+{
+ ulong rgba;
+ F_Tk_color *f = fp;
+ if(tkparsecolor(string2c(f->col), &rgba) != nil)
+ *f->ret = DNotacolor;
+ else
+ *f->ret = rgba;
+}
+
+void
+Tk_rect(void *fp)
+{
+ F_Tk_rect *f = fp;
+ Tk *tk;
+ TkTop *t;
+ Rectangle r;
+ TkGeom *g;
+ Point o;
+ int bd, flags;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop){
+ *(Rectangle *)f->ret = ZR;
+ return;
+ }
+ lockctxt(t->ctxt);
+ tk = tklook(t, string2c(f->name), 0);
+ if(tk == nil){
+ *(Rectangle *)f->ret = ZR;
+ unlockctxt(t->ctxt);
+ return;
+ }
+ o = tkposn(tk);
+ flags = f->flags;
+ if(flags & Tk_Local)
+ o = subpt(o, tkposn(tk->env->top->root));
+ bd = tk->borderwidth;
+ g = (flags & Tk_Required) ? &tk->req : &tk->act;
+ if(flags & Tk_Border){
+ r.min = o;
+ r.max.x = r.min.x + g->width + bd + bd;
+ r.max.y = r.min.y + g->height + bd + bd;
+ } else {
+ r.min.x = o.x + bd;
+ r.min.y = o.y + bd;
+ r.max.x = r.min.x + g->width;
+ r.max.y = r.min.y + g->height;
+ }
+ *(Rectangle *)f->ret = r;
+ unlockctxt(t->ctxt);
+}
+
+int
+tkdescendant(Tk *p, Tk *c)
+{
+ int n;
+
+ if(c == nil || p->env->top != c->env->top)
+ return 0;
+
+ if (p->name != nil && c->name != nil) {
+ n = strlen(p->name->name);
+ if(strncmp(p->name->name, c->name->name, n) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+tkenterleave(TkTop *t)
+{
+ Tk *fw, *ent;
+ TkMouse m;
+ TkTop *t1, *t2;
+ TkCtxt *c;
+
+ c = t->ctxt;
+ m = c->mstate;
+
+ if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
+ fw = tkfindfocus(t, m.x, m.y, 1);
+ if (fw != c->mgrab && fw != nil && (fw->flag & Tknograb) == 0)
+ fw = nil;
+ } else if (c->focused) {
+ fw = tkfindfocus(t, m.x, m.y, 1);
+ if (fw != c->mfocus)
+ fw = nil;
+ } else if (c->mgrab != nil) {
+ fw = tkfindfocus(t, m.x, m.y, 1);
+ if (fw != nil) {
+ if (!tkdescendant(c->mgrab, fw) && !(fw->flag & c->mgrab->flag & Tknograb))
+ fw = nil;
+ }
+ } else if (m.b == 0)
+ fw = tkfindfocus(t, m.x, m.y, 0);
+ else if (tkfindfocus(t, m.x, m.y, 1) == c->entered)
+ return;
+ else
+ fw = nil;
+
+ if (c->entered == fw)
+ return;
+
+ t1 = t2 = nil;
+ if (c->entered != nil) {
+ ent = c->entered;
+ t1 = ent->env->top;
+ c->entered = nil;
+ tkdeliver(ent, TkLeave, nil);
+ }
+
+ if (fw != nil) {
+ t2 = fw->env->top;
+ c->entered = fw;
+ tkdeliver(fw, TkEnter, &m);
+ }
+ if (t1 != nil)
+ tkupdate(t1);
+ if (t2 != nil && t1 != t2)
+ tkupdate(t2);
+}
+
+void
+Tk_pointer(void *a)
+{
+ static int buttonr[] = {TkButton1R, TkButton2R, TkButton3R, TkButton4R, TkButton5R, TkButton6R};
+ static int buttonp[] = {TkButton1P, TkButton2P, TkButton3P, TkButton4P, TkButton5P, TkButton6P};
+ Tk *fw, *target, *dest, *ent;
+ TkMouse m;
+ TkCtxt *c;
+ TkTop *t, *ot;
+ int d, dtype, etype;
+ F_Tk_pointer *f = a;
+ int b, lastb, inside;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop)
+ return;
+
+ c = t->ctxt;
+
+ /* ignore no-button-motion for emulated stylus input */
+ if(tkstylus && c->mstate.b == 0 && (f->p.buttons&0x1f)==0)
+ return;
+
+ lockctxt(c);
+//if (f->p.buttons != 0 || c->mstate.b != 0)
+//print("tkmouse %d [%d %d], focused %d[%s], grab %s, entered %s\n",
+// f->p.buttons, f->p.xy.x, f->p.xy.y, c->focused, tkname(c->mfocus), tkname(c->mgrab), tkname(c->entered));
+ /*
+ * target is the widget that we're deliver the mouse event to.
+ * inside is true if the mouse point is located inside target.
+ */
+ inside = 1;
+ if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
+ fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+ if (fw != nil && (fw->flag & Tknograb))
+ target = fw;
+ else {
+ target = c->mgrab;
+ inside = 0;
+ }
+ } else if (c->focused) {
+ if (c->mfocus != nil) {
+ fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+ if (fw != c->mfocus)
+ inside = 0;
+ }
+ target = c->mfocus;
+ } else if (c->mgrab != nil && (c->mgrab->flag & Tkdisabled) == 0) {
+ /*
+ * XXX this isn't quite right, as perhaps we should do a tkinwindow()
+ * (below the grab).
+ * so that events to containers underneath the grab arrive
+ * via the containers (as is usual)
+ */
+ fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+ if (fw != nil && tkdescendant(c->mgrab, fw))
+ target = fw;
+ else {
+ target = c->mgrab;
+ inside = 0;
+ }
+ } else
+ target = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 0);
+
+ lastb = c->mstate.b;
+ c->mstate.x = f->p.xy.x;
+ c->mstate.y = f->p.xy.y;
+ c->mstate.b = f->p.buttons & 0x1f; /* Just the buttons */
+ m = c->mstate;
+
+ /* XXX if the mouse is being moved with the buttons held down
+ * and we've no mfocus and no mgrab then ignore
+ * the event as our original target has gone away (or never existed)
+ */
+ if (lastb && m.b && !c->focused && c->mgrab == nil)
+ target = nil;
+
+ if (target != c->entered || (c->entered != nil && !inside)) {
+ if (c->entered != nil) {
+ fw = c->entered;
+ c->entered = nil;
+ tkdeliver(fw, TkLeave, nil);
+ if (target == nil || fw->env->top != target->env->top)
+ tkupdate(fw->env->top);
+ }
+ if (inside) {
+ c->entered = target;
+ tkdeliver(target, TkEnter, &m);
+ }
+ }
+
+ dest = nil;
+ if (target != nil) {
+ etype = 0;
+ dtype = 0;
+ if(f->p.buttons & (1<<8)) /* Double */
+ dtype = TkDouble;
+
+ d = lastb ^ m.b;
+ if (d) {
+ /* cancel any autorepeat, notifying existing client */
+ tkrepeat(nil, nil, nil, 0, 0);
+ if (d & ~lastb & 1) /* button 1 potentially takes the focus */
+ tkdeliver(target, TkTakefocus|TkButton1P, &m);
+ }
+ for(b=0; b<nelem(buttonp); b++){
+ if(d & (1<<b)){
+ etype = buttonr[b];
+ if(m.b & (1<<b))
+ etype = buttonp[b]|dtype;
+ dest = tkdeliver(target, etype, &m);
+ }
+ }
+ if(tkstylus && m.b==0) {
+ if ((ent = c->entered) != nil) {
+ c->entered = nil;
+ ot = ent->env->top;
+ tkdeliver(ent, TkLeave, nil);
+ if (ot != target->env->top)
+ tkupdate(ot);
+ }
+ } else if(etype == 0) {
+ etype = TkMotion;
+ for(b = 0; b<nelem(buttonp); b++)
+ if (m.b & (1<<b))
+ etype |= buttonp[b];
+ tkdeliver(target, etype, &m);
+ }
+ if (m.b != 0) {
+ if (lastb == 0 && !c->focused) { /* (some deliver might have grabbed it...) */
+ if (dest == nil)
+ dest = target;
+ if ((dest->flag & Tknograb) == 0) {
+ c->focused = 1;
+ c->mfocus = dest;
+ }
+ }
+ } else {
+ c->focused = 0;
+ c->mfocus = nil;
+ if (lastb != 0)
+ tkenterleave(t);
+ }
+ tkupdate(target->env->top);
+ } else if (c->focused && m.b == 0) {
+ c->focused = 0;
+ tkenterleave(t);
+ }
+ unlockctxt(c);
+}
+
+void
+Tk_keyboard(void *a)
+{
+ Tk *grab;
+ TkTop *t;
+ TkCtxt *c;
+ F_Tk_keyboard *f = a;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop)
+ return;
+ c = t->ctxt;
+ if (c == nil)
+ return;
+ lockctxt(c);
+ if (c->tkmenu != nil)
+ grab = c->tkmenu;
+ else
+ grab = c->tkkeygrab;
+ if(grab == nil){
+ unlockctxt(c);
+ return;
+ }
+
+ t = grab->env->top;
+ tkdeliver(grab, TkKey|TKKEY(f->key), nil);
+ tkupdate(t);
+ unlockctxt(c);
+}
+
+TkVar*
+tkmkvar(TkTop *t, char *name, int type)
+{
+ TkVar *v;
+
+ for(v = t->vars; v; v = v->link)
+ if(strcmp(v->name, name) == 0)
+ return v;
+
+ if(type == 0)
+ return nil;
+
+ v = malloc(sizeof(TkVar)+strlen(name)+1);
+ if(v == nil)
+ return nil;
+ strcpy(v->name, name);
+ v->link = t->vars;
+ t->vars = v;
+ v->type = type;
+ v->value = nil;
+ if(type == TkVchan)
+ v->value = H;
+ return v;
+}
+
+void
+tkfreevar(TkTop *t, char *name, int swept)
+{
+ TkVar **l, *p;
+
+ if(name == nil)
+ return;
+ l = &t->vars;
+ for(p = *l; p != nil; p = p->link) {
+ if(strcmp(p->name, name) == 0) {
+ *l = p->link;
+ switch(p->type) {
+ default:
+ free(p->value);
+ break;
+ case TkVchan:
+ if(!swept)
+ destroy(p->value);
+ break;
+ }
+ free(p);
+ return;
+ }
+ l = &p->link;
+ }
+}
+
+void
+Tk_namechan(void *a)
+{
+ Heap *h;
+ TkVar *v;
+ TkTop *t;
+ char *name;
+ F_Tk_namechan *f = a;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, f->ret);
+ return;
+ }
+ if(f->c == H) {
+ retstr("nil channel", f->ret);
+ return;
+ }
+ name = string2c(f->n);
+ if(name[0] == '\0') {
+ retstr(TkBadvl, f->ret);
+ return;
+ }
+
+ lockctxt(t->ctxt);
+ v = tkmkvar(t, name, TkVchan);
+ if(v == nil) {
+ unlockctxt(t->ctxt);
+ retstr(TkNomem, f->ret);
+ return;
+ }
+ if(v->type != TkVchan) {
+ unlockctxt(t->ctxt);
+ retstr(TkNotvt, f->ret);
+ return;
+ }
+ destroy(v->value);
+ v->value = f->c;
+ unlockctxt(t->ctxt);
+ h = D2H(v->value);
+ h->ref++;
+ Setmark(h);
+ // poolimmutable((void *)h);
+ retstr("", f->ret);
+}
+
+void
+Tk_quote(void *a)
+{
+ String *s, *ns;
+ F_Tk_quote *f;
+ void *r;
+ int c, i, need, len, userune, last, n;
+ Rune *sr;
+ char *sc;
+
+ f = a;
+
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ s = f->s;
+ if(s == H){
+ retstr("{}", f->ret);
+ return;
+ }
+ len = s->len;
+ userune = 0;
+ if(len < 0) {
+ len = -len;
+ userune = 1;
+ }
+ need = len+2;
+ for(i = 0; i < len; i++) {
+ c = userune? s->Srune[i]: s->Sascii[i];
+ if(c == '{' || c == '}' || c == '\\')
+ need++;
+ }
+ if(userune) {
+ ns = newrunes(need);
+ sr = ns->Srune;
+ *sr++ = '{';
+ last = 0;
+ for(i = 0;; i++) {
+ if(i >= len || (c = s->Srune[i]) == '{' || c == '}' || c == '\\'){
+ n = i-last;
+ if(n) {
+ memmove(sr, &s->Srune[last], n*sizeof(Rune));
+ sr += n;
+ }
+ if(i >= len)
+ break;
+ *sr++ = '\\';
+ last = i;
+ }
+ }
+ *sr = '}';
+ } else {
+ ns = newstring(need);
+ sc = ns->Sascii;
+ *sc++ = '{';
+ last = 0;
+ for(i = 0;; i++) {
+ if(i >= len || (c = s->Sascii[i]) == '{' || c == '}' || c == '\\'){
+ n = i-last;
+ if(n) {
+ memmove(sc, &s->Sascii[last], n);
+ sc += n;
+ }
+ if(i >= len)
+ break;
+ *sc++ = '\\';
+ last = i;
+ }
+ }
+ *sc= '}';
+ }
+ *f->ret = ns;
+}
+
+static void
+tkreplimg(TkTop *t, Draw_Image *f, Draw_Image *m, Image **ximg)
+{
+ Display *d;
+ Image *cimg, *cmask, *new;
+
+ cimg = lookupimage(f);
+ d = t->display;
+ if(cimg == nil || cimg->screen != nil || cimg->display != d)
+ return;
+ cmask = lookupimage(m);
+ if(cmask != nil && (cmask->screen != nil || cmask->display != d))
+ return;
+
+ if (cmask == nil)
+ new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), cimg->chan, 0, DNofill);
+ else {
+ if(cmask->screen != nil || cmask->display != d)
+ return;
+ new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), RGBA32, 0, DTransparent);
+ }
+ if(new == nil)
+ return;
+ draw(new, new->r, cimg, cmask, cimg->r.min);
+ if(tkwiretap != nil)
+ tkwiretap(t, "replimg", nil, cimg, &cimg->r);
+ if(*ximg != nil)
+ freeimage(*ximg);
+ *ximg = new;
+}
+
+static char*
+tkaddpanelimage(TkTop *t, Draw_Image *di, Image **i)
+{
+ TkPanelimage *pi;
+
+ if (di == H) {
+ *i = 0;
+ return nil;
+ }
+
+ *i = lookupimage(di);
+ if (*i == nil || (*i)->display != t->display)
+ return TkNotwm;
+
+ for (pi = t->panelimages; pi != nil; pi = pi->link) {
+ if (pi->image == di) {
+ pi->ref++;
+ return nil;
+ }
+ }
+
+ pi = malloc(sizeof(TkPanelimage));
+ if (pi == nil)
+ return TkNomem;
+ pi->image = di;
+ D2H(di)->ref++;
+ pi->ref = 1;
+ pi->link = t->panelimages;
+ t->panelimages = pi;
+ return nil;
+}
+
+void
+tkdelpanelimage(TkTop *t, Image *i)
+{
+ TkPanelimage *pi, *prev;
+ int locked;
+
+ if (i == nil)
+ return;
+
+ prev = nil;
+ for (pi = t->panelimages; pi != nil; pi = pi->link) {
+ if (lookupimage(pi->image) == i)
+ break;
+ prev = pi;
+ }
+ if (pi == nil || --pi->ref > 0)
+ return;
+ if (prev)
+ prev->link = pi->link;
+ else
+ t->panelimages = pi->link;
+ if (D2H(pi->image)->ref == 1) { /* don't bother locking if it's not going away */
+ locked = lockdisplay(t->display);
+ destroy(pi->image);
+ if (locked)
+ unlockdisplay(t->display);
+ }
+
+ free(pi);
+}
+
+void
+Tk_putimage(void *a)
+{
+ TkTop *t;
+ TkImg *tki;
+ Image *i, *m, *oldi, *oldm;
+ int locked, found, reqid, n;
+ char *words[2];
+ Display *d;
+ F_Tk_putimage *f;
+ void *r;
+ char *name, *e;
+ Tk *tk;
+
+ f = a;
+
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, f->ret);
+ return;
+ }
+
+ if(f->i == H) {
+ retstr(TkBadvl, f->ret);
+ return;
+ }
+
+ name = string2c(f->name);
+ lockctxt(t->ctxt);
+ e = nil;
+ found = 0;
+ if(name[0] == '.'){
+ n = getfields(name, words, nelem(words), 1, " ");
+ reqid = -1;
+ if(n > 1){
+ reqid = atoi(words[1]);
+ name = words[0];
+ }
+ if((tk = tklook(t, name, 0)) != nil){
+ if(tk->type == TKchoicebutton){
+ tk = tkfindchoicemenu(tk);
+ if(tk == nil)
+ goto Error;
+ }
+ if(tk->type == TKframe || tk->type == TKmenu){
+ if((tk->flag & Tkwindow) == 0){
+ e = TkNotwm;
+ goto Error;
+ }
+ e = tkputwinimage(tk, f->i, reqid);
+ found = 1;
+ } else
+ if(tk->type == TKpanel){
+ if(n > 1){
+ e = TkBadvl;
+ goto Error;
+ }
+ e = tkaddpanelimage(t, f->i, &i);
+ if(e != nil)
+ goto Error;
+ e = tkaddpanelimage(t, f->m, &m);
+ if(e != nil){
+ tkdelpanelimage(t, i);
+ goto Error;
+ }
+ tkgetpanelimage(tk, &oldi, &oldm);
+ tkdelpanelimage(t, oldi);
+ tkdelpanelimage(t, oldm);
+ tksetpanelimage(tk, i, m);
+ tkdirty(tk);
+ found = 1;
+ }
+ }
+ }
+ if(!found){
+ /* XXX perhaps we shouldn't ever do this if name begins with '.'? */
+ tki = tkname2img(t, name);
+ if(tki == nil) {
+ e = TkBadvl;
+ goto Error;
+ }
+
+ d = t->display;
+ locked = lockdisplay(d);
+ tkreplimg(t, f->i, f->m, &tki->img);
+ if(locked)
+ unlockdisplay(d);
+
+ tksizeimage(t->root, tki);
+ }
+Error:
+ unlockctxt(t->ctxt);
+ if(e != nil)
+ retstr(e, f->ret);
+ return;
+}
+
+Draw_Image*
+tkimgcopy(TkTop *t, Image *cimg)
+{
+ Image *new;
+ Display *dp;
+ Draw_Image *i;
+
+ if(cimg == nil)
+ return H;
+
+ dp = t->display;
+ new = allocimage(dp, cimg->r, cimg->chan, cimg->repl, DNofill);
+ if(new == nil)
+ return H;
+ new->clipr = cimg->clipr;
+
+ drawop(new, new->r, cimg, nil, cimg->r.min, S);
+ if(tkwiretap != nil)
+ tkwiretap(t, "imgcopy", nil, cimg, &cimg->r);
+
+ i = mkdrawimage(new, H, t->dd, nil);
+ if(i == H)
+ freeimage(new);
+
+ return i;
+}
+
+void
+Tk_getimage(void *a)
+{
+ Tk *tk;
+ char *n;
+ TkImg *i;
+ TkTop *t;
+ int locked;
+ Display *d;
+ F_Tk_getimage *f;
+ void *r;
+ void (*getimgs)(Tk*, Image**, Image**);
+ Image *image, *mask;
+
+ f = a;
+
+ r = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(r);
+ r = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(r);
+ r = f->ret->t2;
+ f->ret->t2 = H;
+ destroy(r);
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, &f->ret->t2);
+ return;
+ }
+ d = t->ctxt->display;
+ n = string2c(f->name);
+ lockctxt(t->ctxt);
+ i = tkname2img(t, n);
+ if (i != nil) {
+ image = i->img;
+ mask = nil;
+ } else {
+ tk = tklook(t, n, 0);
+ if (tk == nil || (getimgs = tkmethod[tk->type]->getimgs) == nil) {
+ unlockctxt(t->ctxt);
+ retstr(TkBadvl, &f->ret->t2);
+ return;
+ }
+ getimgs(tk, &image, &mask);
+ }
+ locked = lockdisplay(d);
+ f->ret->t0 = tkimgcopy(t, image);
+ if (mask != nil)
+ f->ret->t1 = tkimgcopy(t, mask);
+ if (locked)
+ unlockdisplay(d);
+ unlockctxt(t->ctxt);
+}
+
+void
+tkfreetop(Heap *h, int swept)
+{
+ TkTop *t;
+ Tk *f;
+ TkImg *i, *nexti;
+ TkVar *v, *nextv;
+ int wgtype;
+ void *r;
+ TkPanelimage *pi, *nextpi;
+
+ t = H2D(TkTop*, h);
+ lockctxt(t->ctxt);
+
+ if(swept) {
+ t->di = H;
+ t->dd = H;
+ t->wreq = H;
+ t->wmctxt = H;
+ }
+
+ t->windows = nil;
+
+ for(f = t->root; f; f = f->siblings) {
+ f->flag |= Tkdestroy;
+ tkdeliver(f, TkDestroy, nil);
+ if(f->destroyed != nil)
+ f->destroyed(f);
+ }
+
+ for(f = t->root; f; f = t->root) {
+ t->root = f->siblings;
+ if(swept)
+ f->flag |= Tkswept;
+ tkfreeobj(f);
+ }
+
+ for(v = t->vars; v; v = nextv) {
+ nextv = v->link;
+ switch(v->type) {
+ default:
+ free(v->value);
+ break;
+ case TkVchan:
+ if(!swept)
+ destroy(v->value);
+ break;
+ }
+ free(v);
+ }
+
+ for (pi = t->panelimages; pi; pi = nextpi) {
+ if (!swept)
+ destroy(pi->image);
+ nextpi = pi->link;
+ free(pi);
+ }
+
+ for(i = t->imgs; i; i = nexti) {
+ if(i->ref != 1)
+ abort();
+ nexti = i->link;
+ tkimgput(i);
+ }
+ /* XXX free images inside widgets */
+
+ for(wgtype = 0; wgtype < TKwidgets; wgtype++)
+ if(t->binds[wgtype])
+ tkfreebind(t->binds[wgtype]);
+
+ unlockctxt(t->ctxt);
+ /* XXX should we leave it locked for this bit? */
+ tkfreectxt(t->ctxt);
+ if(!swept) {
+ r = t->di;
+ t->di = H;
+ destroy(r);
+
+ r = t->dd;
+ t->dd = H;
+ destroy(r);
+
+ r = t->wreq;
+ t->wreq = H;
+ destroy(r);
+
+ r = t->wmctxt;
+ t->wmctxt = H;
+ destroy(r);
+ }
+}
+
+static void
+tktopimagedptr(TkTop *top, Draw_Image *di)
+{
+ if(top->di != H){
+ destroy(top->di);
+ top->di = H;
+ }
+ if(di == H)
+ return;
+ D2H(di)->ref++;
+ top->di = di;
+}
+
+static void
+tkfreewinimage(TkWin *w)
+{
+ destroy(w->di);
+ w->image = nil;
+ w->di = H;
+}
+
+static int
+tksetwindrawimage(Tk *tk, Draw_Image *di)
+{
+ TkWin *tkw;
+ char *name;
+ Image *i;
+ int locked;
+ int same;
+
+ tkw = TKobj(TkWin, tk);
+
+ same = tkw->di == di;
+ if(!same)
+ if(tkw->image != nil)
+ destroy(tkw->di);
+ if(di == H){
+ tkw->di = H;
+ tkw->image = nil;
+ return same;
+ }
+ tkw->di = di;
+ i = lookupimage(di);
+ tkw->image = i;
+
+ locked = lockdisplay(i->display);
+ if(originwindow(i, ZP, i->r.min) == -1)
+ print("tk originwindow failed: %r\n");
+ di->r = DRECT(i->r);
+ di->clipr = DRECT(i->clipr);
+ if(locked)
+ unlockdisplay(i->display);
+
+ if(!same){
+ D2H(di)->ref++;
+ if(tk->name){
+ name = tk->name->name;
+ if(name[0] == '.' && name[1] == '\0')
+ tktopimagedptr(tk->env->top, tkw->di);
+ }
+ }
+ return same;
+}
+
+void
+tkdestroywinimage(Tk *tk)
+{
+ TkWin *tkw;
+ TkTop *top;
+ char *name;
+
+ assert(tk->flag & Tkwindow);
+ tkw = TKobj(TkWin, tk);
+ top = tk->env->top;
+
+ if(tkw->image != nil && !(tk->flag & Tkswept))
+ destroy(tkw->di);
+ tkw->di = H;
+ tkw->image = nil;
+ if(tk->name == nil)
+ name = tkw->cbname;
+ else
+ name = tk->name->name;
+ if(name[0] == '.' && name[1] == '\0' && !(tk->flag & Tkswept))
+ tktopimagedptr(top, H);
+ tkw->reqid++;
+ tkwreq(top, "delete %s", name);
+}
+
+static char*
+tkputwinimage(Tk *tk, Draw_Image *di, int reqid)
+{
+ TkWin *tkw;
+ TkTop *top;
+ Image *i;
+ int bw2, prop, resize;
+ Rectangle req;
+
+ top = tk->env->top;
+ tkw = TKobj(TkWin, tk);
+ i = lookupimage(di);
+ if (i == nil || i->display != top->display)
+ return TkNotwm;
+
+ if(reqid != -1 && reqid < tkw->reqid)
+ return "!request out of date";
+
+ bw2 = 2*tk->borderwidth;
+ req.min.x = tkw->req.x;
+ req.min.y = tkw->req.y;
+ req.max.x = req.min.x + tk->act.width + bw2;
+ req.max.y = req.min.y + tk->act.height + bw2;
+
+ resize = 0;
+ if(eqrect(req, i->r) == 0){
+ /*
+ * if we'd sent a request and our requested rect has now changed,
+ * then resend the request (via tkupdatewinsize),
+ * otherwise accept the new size and repack if necessary
+ */
+ if(reqid != -1 && tkw->changed){
+ if(tkupdatewinsize(tk))
+ return "!requested size has changed";
+
+ } else if(Dx(req) != Dx(i->r) || Dy(req) != Dy(i->r)){
+ tk->flag |= Tksuspended;
+ tk->act.width = Dx(i->r) - bw2;
+ tk->act.height = Dy(i->r) - bw2;
+ tk->req = tk->act;
+ prop = tk->flag & Tknoprop;
+ tk->flag |= Tknoprop;
+ tkpackqit(tk);
+ tkrunpack(top);
+ tk->flag = (tk->flag & ~Tknoprop) | prop;
+ resize = 1;
+ }
+ }
+ if(reqid == -1)
+ tkw->reqid++; /* invalidate all buffered requests. */
+ tkw->act = i->r.min;
+ tkw->req = tkw->act;
+ tkw->changed = 0;
+ tk->req.width = Dx(i->r) - bw2;
+ tk->req.height = Dy(i->r) - bw2;
+ tk->act = tk->req;
+ if((tk->flag & Tkmapped) == 0){
+ tk->flag |= Tkmapped;
+ tkdeliver(tk, TkMap, nil);
+ }
+ if(tksetwindrawimage(tk, di) == 0 || resize){
+ tk->dirty = tkrect(tk, 1);
+ tk->flag |= Tkrefresh;
+ }
+ tk->flag &= ~Tksuspended;
+
+ lookupimage(di); /* make sure limbo image coords correspond correctly */
+ tkupdate(top);
+ return nil;
+}
+
+void
+tkwreq(TkTop *top, char *fmt, ...)
+{
+ char *buf;
+ va_list arg;
+
+ va_start(arg, fmt);
+ buf = vsmprint(fmt, arg);
+ va_end(arg);
+ tktolimbo(top->wreq, buf);
+ free(buf);
+}
+
+int
+tktolimbo(void *var, char *msg)
+{
+ void *ptrs[1];
+ int r;
+
+ if(var==H)
+ return 0;
+ ptrs[0] = H;
+ retstr(msg, (String**) &ptrs[0]);
+ r = csendalt((Channel *)var, ptrs, &Tptr, TkMaxmsgs);
+ return r;
+}
+
+static void
+hexify(char *buf, int n)
+{
+ static char hex[] = "0123456789abcdef";
+ uchar b;
+ char *dp, *fp;
+ fp = buf+n;
+ dp = buf+n*2;
+ *dp-- = '\0';
+ while(fp-- > buf){
+ b = (uchar)*fp;
+ *dp-- = hex[b & 0xf];
+ *dp-- = hex[b >> 4];
+ }
+}
+
+char*
+tkcursorswitch(TkTop *top, Image *i, TkImg *img)
+{
+ Image *ci, *scratch;
+ char *buf;
+ Rectangle r;
+ int n, maxb, nb;
+
+ if(i == nil && img == nil){
+ tktolimbo(top->wreq, "cursor");
+ return nil;
+ }
+
+ if(img != nil){
+ if(img->cursor){
+ tktolimbo(top->wreq, img->cursor);
+ return nil;
+ }
+ i = img->img;
+ }
+ if(i->depth != 1 || Dx(i->r)*Dy(i->r) > 16000 || Dy(i->r)%8 != 0 || Dy(i->r)%2 != 0)
+ return TkBadcursor;
+ /*
+ * readjust image, inferring hotspot from origin.
+ */
+ if(i->r.min.x != 0 || i->r.min.y != 0){
+ r.min.x = 0;
+ r.min.y = 0;
+ r.max.x = Dx(i->r);
+ r.max.y = Dy(i->r);
+ scratch = allocimage(i->display, r, GREY1, 0, DNofill);
+ if(scratch == nil)
+ return TkNomem;
+ draw(scratch, r, i, nil, i->r.min);
+ ci = scratch;
+ }else{
+ scratch = nil;
+ ci = i;
+ }
+ nb = ci->r.max.x/8 * ci->r.max.y;
+ maxb = 7 + 12*4 + 2*nb + 1;
+ buf = mallocz(maxb, 0);
+ if(buf == nil)
+ return TkNomem;
+ n = sprint(buf, "cursor %d %d %d %d ", i->r.min.x, i->r.min.y, ci->r.max.x, ci->r.max.y);
+ unloadimage(ci, ci->r, (uchar*)buf+n, maxb-n);
+ hexify(buf+n, nb);
+ tktolimbo(top->wreq, buf);
+ if(img != nil){
+ free(img->cursor);
+ img->cursor = buf;
+ }
+ freeimage(scratch);
+ return nil;
+}
+
+void
+tkcursorset(TkTop *t, Point p)
+{
+ tkwreq(t, "ptr %d %d", p.x, p.y);
+}
diff --git a/libinterp/tkmod.h b/libinterp/tkmod.h
new file mode 100644
index 00000000..0b8b97a0
--- /dev/null
+++ b/libinterp/tkmod.h
@@ -0,0 +1,15 @@
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+Runtab Tkmodtab[]={
+ "cmd",0x1ee9697,Tk_cmd,40,2,{0x0,0xc0,},
+ "color",0xc6935858,Tk_color,40,2,{0x0,0x80,},
+ "getimage",0x80bea378,Tk_getimage,40,2,{0x0,0xc0,},
+ "keyboard",0x8671bae6,Tk_keyboard,40,2,{0x0,0x80,},
+ "namechan",0x35182638,Tk_namechan,48,2,{0x0,0xe0,},
+ "pointer",0x21188625,Tk_pointer,56,2,{0x0,0x80,},
+ "putimage",0x2dc55622,Tk_putimage,48,2,{0x0,0xf0,},
+ "quote",0xb2cd7190,Tk_quote,40,2,{0x0,0x80,},
+ "rect",0x683e6bae,Tk_rect,48,2,{0x0,0xc0,},
+ "toplevel",0x96ab1cc9,Tk_toplevel,40,2,{0x0,0xc0,},
+ 0
+};
+#define Tkmodlen 10
diff --git a/libinterp/validstk.c b/libinterp/validstk.c
new file mode 100644
index 00000000..6956a641
--- /dev/null
+++ b/libinterp/validstk.c
@@ -0,0 +1,53 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+static int depth;
+
+void
+memchk(void *p, Type *t)
+{
+ Heap *h;
+ int i, j;
+ ulong *v, **base;
+
+ if(depth > 100)
+ return;
+ depth++;
+ base = p;
+ for(i = 0; i < t->np; i++) {
+ for(j = 0; j < 8; j++) {
+ if(t->map[i] & (1<<(7-j))) {
+ v = base[(i*8)+j];
+ if(v != H) {
+ h = D2H(v);
+ hmsize(h);
+ if(h->ref <= 0)
+ abort();
+ if(h->t != nil)
+ memchk(v, h->t);
+ }
+ }
+ }
+ }
+ depth--;
+}
+
+void
+validstk(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *fp;
+
+ fp = R.FP;
+ while(fp != nil) {
+ f = (Frame*)fp;
+ t = f->t;
+ if(t == nil)
+ t = SEXTYPE(f)->reg.TR;
+
+ memchk(f, t);
+ fp = f->fp;
+ }
+}
diff --git a/libinterp/xec.c b/libinterp/xec.c
new file mode 100644
index 00000000..9f6792e9
--- /dev/null
+++ b/libinterp/xec.c
@@ -0,0 +1,1692 @@
+#include <lib9.h>
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+REG R; /* Virtual Machine registers */
+String snil; /* String known to be zero length */
+
+#define Stmp *((WORD*)(R.FP+NREG*IBY2WD))
+#define Dtmp *((WORD*)(R.FP+(NREG+2)*IBY2WD))
+
+#define OP(fn) void fn(void)
+#define B(r) *((BYTE*)(R.r))
+#define W(r) *((WORD*)(R.r))
+#define UW(r) *((UWORD*)(R.r))
+#define F(r) *((REAL*)(R.r))
+#define V(r) *((LONG*)(R.r))
+#define UV(r) *((ULONG*)(R.r))
+#define S(r) *((String**)(R.r))
+#define A(r) *((Array**)(R.r))
+#define L(r) *((List**)(R.r))
+#define P(r) *((WORD**)(R.r))
+#define C(r) *((Channel**)(R.r))
+#define T(r) *((void**)(R.r))
+#define JMP(r) R.PC = *(Inst**)(R.r)
+#define SH(r) *((SHORT*)(R.r))
+#define SR(r) *((SREAL*)(R.r))
+
+OP(runt) {}
+OP(negf) { F(d) = -F(s); }
+OP(jmp) { JMP(d); }
+OP(movpc){ T(d) = &R.M->prog[W(s)]; }
+OP(movm) { memmove(R.d, R.s, W(m)); }
+OP(lea) { W(d) = (WORD)R.s; }
+OP(movb) { B(d) = B(s); }
+OP(movw) { W(d) = W(s); }
+OP(movf) { F(d) = F(s); }
+OP(movl) { V(d) = V(s); }
+OP(cvtbw){ W(d) = B(s); }
+OP(cvtwb){ B(d) = W(s); }
+OP(cvtrf){ F(d) = SR(s); }
+OP(cvtfr){ SR(d) = F(s); }
+OP(cvtws){ SH(d) = W(s); }
+OP(cvtsw){ W(d) = SH(s); }
+OP(cvtwf){ F(d) = W(s); }
+OP(addb) { B(d) = B(m) + B(s); }
+OP(addw) { W(d) = W(m) + W(s); }
+OP(addl) { V(d) = V(m) + V(s); }
+OP(addf) { F(d) = F(m) + F(s); }
+OP(subb) { B(d) = B(m) - B(s); }
+OP(subw) { W(d) = W(m) - W(s); }
+OP(subl) { V(d) = V(m) - V(s); }
+OP(subf) { F(d) = F(m) - F(s); }
+OP(divb) { B(d) = B(m) / B(s); }
+OP(divw) { W(d) = W(m) / W(s); }
+OP(divl) { V(d) = V(m) / V(s); }
+OP(divf) { F(d) = F(m) / F(s); }
+OP(modb) { B(d) = B(m) % B(s); }
+OP(modw) { W(d) = W(m) % W(s); }
+OP(modl) { V(d) = V(m) % V(s); }
+OP(mulb) { B(d) = B(m) * B(s); }
+OP(mulw) { W(d) = W(m) * W(s); }
+OP(mull) { V(d) = V(m) * V(s); }
+OP(mulf) { F(d) = F(m) * F(s); }
+OP(andb) { B(d) = B(m) & B(s); }
+OP(andw) { W(d) = W(m) & W(s); }
+OP(andl) { V(d) = V(m) & V(s); }
+OP(xorb) { B(d) = B(m) ^ B(s); }
+OP(xorw) { W(d) = W(m) ^ W(s); }
+OP(xorl) { V(d) = V(m) ^ V(s); }
+OP(orb) { B(d) = B(m) | B(s); }
+OP(orw) { W(d) = W(m) | W(s); }
+OP(orl) { V(d) = V(m) | V(s); }
+OP(shlb) { B(d) = B(m) << W(s); }
+OP(shlw) { W(d) = W(m) << W(s); }
+OP(shll) { V(d) = V(m) << W(s); }
+OP(shrb) { B(d) = B(m) >> W(s); }
+OP(shrw) { W(d) = W(m) >> W(s); }
+OP(shrl) { V(d) = V(m) >> W(s); }
+OP(lsrw) { W(d) = UW(m) >> W(s); }
+OP(lsrl) { V(d) = UV(m) >> W(s); }
+OP(beqb) { if(B(s) == B(m)) JMP(d); }
+OP(bneb) { if(B(s) != B(m)) JMP(d); }
+OP(bltb) { if(B(s) < B(m)) JMP(d); }
+OP(bleb) { if(B(s) <= B(m)) JMP(d); }
+OP(bgtb) { if(B(s) > B(m)) JMP(d); }
+OP(bgeb) { if(B(s) >= B(m)) JMP(d); }
+OP(beqw) { if(W(s) == W(m)) JMP(d); }
+OP(bnew) { if(W(s) != W(m)) JMP(d); }
+OP(bltw) { if(W(s) < W(m)) JMP(d); }
+OP(blew) { if(W(s) <= W(m)) JMP(d); }
+OP(bgtw) { if(W(s) > W(m)) JMP(d); }
+OP(bgew) { if(W(s) >= W(m)) JMP(d); }
+OP(beql) { if(V(s) == V(m)) JMP(d); }
+OP(bnel) { if(V(s) != V(m)) JMP(d); }
+OP(bltl) { if(V(s) < V(m)) JMP(d); }
+OP(blel) { if(V(s) <= V(m)) JMP(d); }
+OP(bgtl) { if(V(s) > V(m)) JMP(d); }
+OP(bgel) { if(V(s) >= V(m)) JMP(d); }
+OP(beqf) { if(F(s) == F(m)) JMP(d); }
+OP(bnef) { if(F(s) != F(m)) JMP(d); }
+OP(bltf) { if(F(s) < F(m)) JMP(d); }
+OP(blef) { if(F(s) <= F(m)) JMP(d); }
+OP(bgtf) { if(F(s) > F(m)) JMP(d); }
+OP(bgef) { if(F(s) >= F(m)) JMP(d); }
+OP(beqc) { if(stringcmp(S(s), S(m)) == 0) JMP(d); }
+OP(bnec) { if(stringcmp(S(s), S(m)) != 0) JMP(d); }
+OP(bltc) { if(stringcmp(S(s), S(m)) < 0) JMP(d); }
+OP(blec) { if(stringcmp(S(s), S(m)) <= 0) JMP(d); }
+OP(bgtc) { if(stringcmp(S(s), S(m)) > 0) JMP(d); }
+OP(bgec) { if(stringcmp(S(s), S(m)) >= 0) JMP(d); }
+OP(iexit){ error(""); }
+OP(cvtwl){ V(d) = W(s); }
+OP(cvtlw){ W(d) = V(s); }
+OP(cvtlf){ F(d) = V(s); }
+OP(cvtfl)
+{
+ REAL f;
+
+ f = F(s);
+ V(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtfw)
+{
+ REAL f;
+
+ f = F(s);
+ W(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtcl)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ V(d) = 0;
+ else
+ V(d) = strtoll(string2c(s), nil, 10);
+}
+OP(iexpw)
+{
+ int inv;
+ WORD x, n, r;
+
+ x = W(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ W(d) = r;
+}
+OP(iexpl)
+{
+ int inv;
+ WORD n;
+ LONG x, r;
+
+ x = V(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ V(d) = r;
+}
+OP(iexpf)
+{
+ int inv;
+ WORD n;
+ REAL x, r;
+
+ x = F(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ F(d) = r;
+}
+OP(indx)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*a->t->size);
+}
+OP(indw)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(WORD));
+}
+OP(indf)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(REAL));
+}
+OP(indl)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(LONG));
+}
+OP(indb)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(BYTE));
+}
+OP(movp)
+{
+ Heap *h;
+ WORD *dv, *sv;
+
+ sv = P(s);
+ if(sv != H) {
+ h = D2H(sv);
+ h->ref++;
+ Setmark(h);
+ }
+ dv = P(d);
+ P(d) = sv;
+ destroy(dv);
+}
+OP(movmp)
+{
+ Type *t;
+
+ t = R.M->type[W(m)];
+
+ incmem(R.s, t);
+ if (t->np)
+ freeptrs(R.d, t);
+ memmove(R.d, R.s, t->size);
+}
+OP(new)
+{
+ Heap *h;
+ WORD **wp, *t;
+
+ h = heap(R.M->type[W(s)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(newz)
+{
+ Heap *h;
+ WORD **wp, *t;
+
+ h = heapz(R.M->type[W(s)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(mnewz)
+{
+ Heap *h;
+ WORD **wp, *t;
+ Modlink *ml;
+
+ ml = *(Modlink**)R.s;
+ if(ml == H)
+ error(exModule);
+ h = heapz(ml->type[W(m)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(frame)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = R.M->type[W(s)];
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ if (t->np)
+ initmem(t, f);
+ T(d) = f;
+}
+OP(mframe)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.s;
+ if(ml == H)
+ error(exModule);
+
+ o = W(m);
+ if(o >= 0){
+ if(o >= ml->nlinks)
+ error("invalid mframe");
+ t = ml->links[o].frame;
+ }
+ else
+ t = ml->m->ext[-o-1].frame;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ if (t->np)
+ initmem(t, f);
+ T(d) = f;
+}
+void
+acheck(int tsz, int sz)
+{
+ if(sz < 0)
+ error(exNegsize);
+ /* test for overflow; assumes sz >>> tsz */
+ if((int)(sizeof(Array) + sizeof(Heap) + tsz*sz) < sz && tsz != 0)
+ error(exHeap);
+}
+OP(newa)
+{
+ int sz;
+ Type *t;
+ Heap *h;
+ Array *a, *at, **ap;
+
+ t = R.M->type[W(m)];
+ sz = W(s);
+ acheck(t->size, sz);
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ initarray(t, a);
+
+ ap = R.d;
+ at = *ap;
+ *ap = a;
+ destroy(at);
+}
+OP(newaz)
+{
+ int sz;
+ Type *t;
+ Heap *h;
+ Array *a, *at, **ap;
+
+ t = R.M->type[W(m)];
+ sz = W(s);
+ acheck(t->size, sz);
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ memset(a->data, 0, t->size*sz);
+ initarray(t, a);
+
+ ap = R.d;
+ at = *ap;
+ *ap = a;
+ destroy(at);
+}
+Channel*
+cnewc(Type *t, void (*mover)(void), int len)
+{
+ Heap *h;
+ Channel *c;
+
+ h = heap(&Tchannel);
+ c = H2D(Channel*, h);
+ c->send = (Progq*)malloc(sizeof(Progq));
+ c->recv = (Progq*)malloc(sizeof(Progq));
+ if(c->send == nil || c->recv == nil){
+ free(c->send);
+ free(c->recv);
+ error(exNomem);
+ }
+ c->send->prog = c->recv->prog = nil;
+ c->send->next = c->recv->next = nil;
+ c->mover = mover;
+ c->buf = H;
+ if(len > 0)
+ c->buf = H2D(Array*, heaparray(t, len));
+ c->front = 0;
+ c->size = 0;
+ if(mover == movtmp){
+ c->mid.t = t;
+ t->ref++;
+ }
+ return c;
+}
+Channel*
+newc(Type *t, void (*mover)(void))
+{
+ Channel **cp, *oldc;
+ WORD len;
+
+ len = 0;
+ if(R.m != R.d){
+ len = W(m);
+ if(len < 0)
+ error(exNegsize);
+ }
+ cp = R.d;
+ oldc = *cp;
+ *cp = cnewc(t, mover, len);
+ destroy(oldc);
+ return *cp;
+}
+OP(newcl) { newc(&Tlong, movl); }
+OP(newcb) { newc(&Tbyte, movb); }
+OP(newcw) { newc(&Tword, movw); }
+OP(newcf) { newc(&Treal, movf); }
+OP(newcp) { newc(&Tptr, movp); }
+OP(newcm)
+{
+ Channel *c;
+ Type *t;
+
+ t = nil;
+ if(R.m != R.d && W(m) > 0)
+ t = dtype(nil, W(s), nil, 0);
+ c = newc(t, movm);
+ c->mid.w = W(s);
+ if(t != nil)
+ freetype(t);
+}
+OP(newcmp)
+{
+ newc(R.M->type[W(s)], movtmp);
+}
+OP(icase)
+{
+ WORD v, *t, *l, d, n, n2;
+
+ v = W(s);
+ t = (WORD*)((WORD)R.d + IBY2WD);
+ n = t[-1];
+ d = t[n*3];
+
+ while(n > 0) {
+ n2 = n >> 1;
+ l = t + n2*3;
+ if(v < l[0]) {
+ n = n2;
+ continue;
+ }
+ if(v >= l[1]) {
+ t = l+3;
+ n -= n2 + 1;
+ continue;
+ }
+ d = l[2];
+ break;
+ }
+ if(R.M->compiled) {
+ R.PC = (Inst*)d;
+ return;
+ }
+ R.PC = R.M->prog + d;
+}
+OP(casel)
+{
+ WORD *t, *l, d, n, n2;
+ LONG v;
+
+ v = V(s);
+ t = (WORD*)((WORD)R.d + 2*IBY2WD);
+ n = t[-2];
+ d = t[n*6];
+
+ while(n > 0) {
+ n2 = n >> 1;
+ l = t + n2*6;
+ if(v < ((LONG*)l)[0]) {
+ n = n2;
+ continue;
+ }
+ if(v >= ((LONG*)l)[1]) {
+ t = l+6;
+ n -= n2 + 1;
+ continue;
+ }
+ d = l[4];
+ break;
+ }
+ if(R.M->compiled) {
+ R.PC = (Inst*)d;
+ return;
+ }
+ R.PC = R.M->prog + d;
+}
+OP(casec)
+{
+ WORD *l, *t, *e, n, n2, r;
+ String *sl, *sh, *sv;
+
+ sv = S(s);
+ t = (WORD*)((WORD)R.d + IBY2WD);
+ n = t[-1];
+ e = t + n*3;
+ if(n > 2){
+ while(n > 0){
+ n2 = n>>1;
+ l = t + n2*3;
+ sl = (String*)l[0];
+ r = stringcmp(sv, sl);
+ if(r == 0){
+ e = &l[2];
+ break;
+ }
+ if(r < 0){
+ n = n2;
+ continue;
+ }
+ sh = (String*)l[1];
+ if(sh == H || stringcmp(sv, sh) > 0){
+ t = l+3;
+ n -= n2+1;
+ continue;
+ }
+ e = &l[2];
+ break;
+ }
+ t = e;
+ }
+ else{
+ while(t < e) {
+ sl = (String*)t[0];
+ sh = (String*)t[1];
+ if(sh == H) {
+ if(stringcmp(sl, sv) == 0) {
+ t = &t[2];
+ goto found;
+ }
+ }
+ else
+ if(stringcmp(sl, sv) <= 0 && stringcmp(sh, sv) >= 0) {
+ t = &t[2];
+ goto found;
+ }
+ t += 3;
+ }
+ }
+found:
+ if(R.M->compiled) {
+ R.PC = (Inst*)*t;
+ return;
+ }
+ R.PC = R.M->prog + t[0];
+}
+OP(igoto)
+{
+ WORD *t;
+
+ t = (WORD*)((WORD)R.d + (W(s) * IBY2WD));
+ if(R.M->compiled) {
+ R.PC = (Inst*)t[0];
+ return;
+ }
+ R.PC = R.M->prog + t[0];
+}
+OP(call)
+{
+ Frame *f;
+
+ f = T(s);
+ f->lr = R.PC;
+ f->fp = R.FP;
+ R.FP = (uchar*)f;
+ JMP(d);
+}
+OP(spawn)
+{
+ Prog *p;
+
+ p = newprog(currun(), R.M);
+ p->R.PC = *(Inst**)R.d;
+ newstack(p);
+ unframe();
+}
+OP(mspawn)
+{
+ Prog *p;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.d;
+ if(ml == H)
+ error(exModule);
+ if(ml->prog == nil)
+ error(exSpawn);
+ p = newprog(currun(), ml);
+ o = W(m);
+ if(o >= 0)
+ p->R.PC = ml->links[o].u.pc;
+ else
+ p->R.PC = ml->m->ext[-o-1].u.pc;
+ newstack(p);
+ unframe();
+}
+OP(ret)
+{
+ Frame *f;
+ Modlink *m;
+
+ f = (Frame*)R.FP;
+ R.FP = f->fp;
+ if(R.FP == nil) {
+ R.FP = (uchar*)f;
+ error("");
+ }
+ R.SP = (uchar*)f;
+ R.PC = f->lr;
+ m = f->mr;
+
+ if(f->t == nil)
+ unextend(f);
+ else if (f->t->np)
+ freeptrs(f, f->t);
+
+ if(m != nil) {
+ if(R.M->compiled != m->compiled) {
+ R.IC = 1;
+ R.t = 1;
+ }
+ destroy(R.M);
+ R.M = m;
+ R.MP = m->MP;
+ }
+}
+OP(iload)
+{
+ char *n;
+ Import *ldt;
+ Module *m;
+ Modlink *ml, **mp, *t;
+
+ n = string2c(S(s));
+ m = R.M->m;
+ if(m->rt & HASLDT)
+ ldt = m->ldt[W(m)];
+ else{
+ ldt = nil;
+ error("obsolete dis");
+ }
+
+ if(strcmp(n, "$self") == 0) {
+ m->ref++;
+ ml = linkmod(m, ldt, 0);
+ if(ml != H) {
+ ml->MP = R.M->MP;
+ D2H(ml->MP)->ref++;
+ }
+ }
+ else {
+ m = readmod(n, lookmod(n), 1);
+ ml = linkmod(m, ldt, 1);
+ }
+
+ mp = R.d;
+ t = *mp;
+ *mp = ml;
+ destroy(t);
+}
+OP(mcall)
+{
+ Heap *h;
+ Prog *p;
+ Frame *f;
+ Linkpc *l;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.d;
+ if(ml == H)
+ error(exModule);
+ f = T(s);
+ f->lr = R.PC;
+ f->fp = R.FP;
+ f->mr = R.M;
+
+ R.FP = (uchar*)f;
+ R.M = ml;
+ h = D2H(ml);
+ h->ref++;
+
+ o = W(m);
+ if(o >= 0)
+ l = &ml->links[o].u;
+ else
+ l = &ml->m->ext[-o-1].u;
+ if(ml->prog == nil) {
+ l->runt(f);
+ h->ref--;
+ R.M = f->mr;
+ R.SP = R.FP;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else if (f->t->np)
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+ R.t = 0;
+ return;
+ }
+ R.MP = R.M->MP;
+ R.PC = l->pc;
+ R.t = 1;
+
+ if(f->mr->compiled != R.M->compiled)
+ R.IC = 1;
+}
+OP(lena)
+{
+ WORD l;
+ Array *a;
+
+ a = A(s);
+ l = 0;
+ if(a != H)
+ l = a->len;
+ W(d) = l;
+}
+OP(lenl)
+{
+ WORD l;
+ List *a;
+
+ a = L(s);
+ l = 0;
+ while(a != H) {
+ l++;
+ a = a->tail;
+ }
+ W(d) = l;
+}
+static int
+cgetb(Channel *c, void *v)
+{
+ Array *a;
+ void *w;
+
+ if((a = c->buf) == H)
+ return 0;
+ if(c->size > 0){
+ w = a->data+c->front*a->t->size;
+ c->front++;
+ if(c->front == c->buf->len)
+ c->front = 0;
+ c->size--;
+ R.s = w;
+ R.m = &c->mid;
+ R.d = v;
+ c->mover();
+ if(a->t->np){
+ freeptrs(w, a->t);
+ initmem(a->t, w);
+ }
+ return 1;
+ }
+ return 0;
+}
+static int
+cputb(Channel *c, void *v)
+{
+ Array *a;
+ WORD len, r;
+
+ if((a = c->buf) == H)
+ return 0;
+ len = c->buf->len;
+ if(c->size < len){
+ r = c->front+c->size;
+ if(r >= len)
+ r -= len;
+ c->size++;
+ R.s = v;
+ R.m = &c->mid;
+ R.d = a->data+r*a->t->size;
+ c->mover();
+ return 1;
+ }
+ return 0;
+}
+/*
+int
+cqsize(Progq *q)
+{
+ int n;
+
+ n = 0;
+ for( ; q != nil; q = q->next)
+ if(q->prog != nil)
+ n++;
+ return n;
+}
+*/
+void
+cqadd(Progq **q, Prog *p)
+{
+ Progq *n;
+
+ if((*q)->prog == nil){
+ (*q)->prog = p;
+ return;
+ }
+ n = (Progq*)malloc(sizeof(Progq));
+ if(n == nil)
+ error(exNomem);
+ n->prog = p;
+ n->next = nil;
+ for( ; *q != nil; q = &(*q)->next)
+ ;
+ *q = n;
+}
+void
+cqdel(Progq **q)
+{
+ Progq *f;
+
+ if((*q)->next == nil){
+ (*q)->prog = nil;
+ return;
+ }
+ f = *q;
+ *q = f->next;
+ free(f);
+}
+void
+cqdelp(Progq **q, Prog *p)
+{
+ Progq *f;
+
+ if((*q)->next == nil){
+ if((*q)->prog == p)
+ (*q)->prog = nil;
+ return;
+ }
+ for( ; *q != nil; ){
+ if((*q)->prog == p){
+ f = *q;
+ *q = (*q)->next;
+ free(f);
+ }
+ else
+ q = &(*q)->next;
+ }
+}
+OP(isend)
+{
+ Channel *c;
+ Prog *p;
+
+ c = C(d);
+ if(c == H)
+ error(exNilref);
+
+ if((p = c->recv->prog) == nil) {
+ if(c->buf != H && cputb(c, R.s))
+ return;
+ p = delrun(Psend);
+ p->ptr = R.s;
+ p->chan = c; /* for killprog */
+ R.IC = 1;
+ R.t = 1;
+ cqadd(&c->send, p);
+ return;
+ }
+
+ if(c->buf != H && c->size > 0)
+ print("non-empty buffer in isend\n");
+
+ cqdel(&c->recv);
+ if(p->state == Palt)
+ altdone(p->R.s, p, c, 1);
+
+ R.m = &c->mid;
+ R.d = p->ptr;
+ p->ptr = nil;
+ c->mover();
+ addrun(p);
+ R.t = 0;
+}
+OP(irecv)
+{
+ Channel *c;
+ Prog *p;
+
+ c = C(s);
+ if(c == H)
+ error(exNilref);
+
+ if((p = c->send->prog) == nil) {
+ if(c->buf != H && cgetb(c, R.d))
+ return;
+ p = delrun(Precv);
+ p->ptr = R.d;
+ p->chan = c; /* for killprog */
+ R.IC = 1;
+ R.t = 1;
+ cqadd(&c->recv, p);
+ return;
+ }
+
+ if(c->buf != H && c->size != c->buf->len)
+ print("non-full buffer in irecv\n");
+
+ cqdel(&c->send);
+ if(p->state == Palt)
+ altdone(p->R.s, p, c, 0);
+
+ if(c->buf != H){
+ cgetb(c, R.d);
+ cputb(c, p->ptr);
+ p->ptr = nil;
+ }
+ else{
+ R.m = &c->mid;
+ R.s = p->ptr;
+ p->ptr = nil;
+ c->mover();
+ }
+ addrun(p);
+ R.t = 0;
+}
+int
+csendalt(Channel *c, void *ip, Type *t, int len)
+{
+ REG rsav;
+
+ if(c == H)
+ error(exNilref);
+
+ if(c->recv->prog == nil && (c->buf == H || c->size == c->buf->len)){
+ if(c->buf != H){
+ print("csendalt failed\n");
+ freeptrs(ip, t);
+ return 0;
+ }
+ c->buf = H2D(Array*, heaparray(t, len));
+ }
+
+ rsav = R;
+ R.s = ip;
+ R.d = &c;
+ isend();
+ R = rsav;
+ freeptrs(ip, t);
+ return 1;
+}
+
+List*
+cons(ulong size, List **lp)
+{
+ Heap *h;
+ List *lv, *l;
+
+ h = nheap(sizeof(List) + size - sizeof(((List*)0)->data));
+ h->t = &Tlist;
+ Tlist.ref++;
+ l = H2D(List*, h);
+ l->t = nil;
+
+ lv = *lp;
+ if(lv != H) {
+ h = D2H(lv);
+ Setmark(h);
+ }
+ l->tail = lv;
+ *lp = l;
+ return l;
+}
+OP(consb)
+{
+ List *l;
+
+ l = cons(IBY2WD, R.d);
+ *(BYTE*)l->data = B(s);
+}
+OP(consw)
+{
+ List *l;
+
+ l = cons(IBY2WD, R.d);
+ *(WORD*)l->data = W(s);
+}
+OP(consl)
+{
+ List *l;
+
+ l = cons(IBY2LG, R.d);
+ *(LONG*)l->data = V(s);
+}
+OP(consp)
+{
+ List *l;
+ Heap *h;
+ WORD *sv;
+
+ l = cons(IBY2WD, R.d);
+ sv = P(s);
+ if(sv != H) {
+ h = D2H(sv);
+ h->ref++;
+ Setmark(h);
+ }
+ l->t = &Tptr;
+ Tptr.ref++;
+ *(WORD**)l->data = sv;
+}
+OP(consf)
+{
+ List *l;
+
+ l = cons(sizeof(REAL), R.d);
+ *(REAL*)l->data = F(s);
+}
+OP(consm)
+{
+ int v;
+ List *l;
+
+ v = W(m);
+ l = cons(v, R.d);
+ memmove(l->data, R.s, v);
+}
+OP(consmp)
+{
+ List *l;
+ Type *t;
+
+ t = R.M->type[W(m)];
+ l = cons(t->size, R.d);
+ incmem(R.s, t);
+ memmove(l->data, R.s, t->size);
+ l->t = t;
+ t->ref++;
+}
+OP(headb)
+{
+ List *l;
+
+ l = L(s);
+ B(d) = *(BYTE*)l->data;
+}
+OP(headw)
+{
+ List *l;
+
+ l = L(s);
+ W(d) = *(WORD*)l->data;
+}
+OP(headl)
+{
+ List *l;
+
+ l = L(s);
+ V(d) = *(LONG*)l->data;
+}
+OP(headp)
+{
+ List *l;
+
+ l = L(s);
+ R.s = l->data;
+ movp();
+}
+OP(headf)
+{
+ List *l;
+
+ l = L(s);
+ F(d) = *(REAL*)l->data;
+}
+OP(headm)
+{
+ List *l;
+
+ l = L(s);
+ memmove(R.d, l->data, W(m));
+}
+OP(headmp)
+{
+ List *l;
+
+ l = L(s);
+ R.s = l->data;
+ movmp();
+}
+OP(tail)
+{
+ List *l;
+
+ l = L(s);
+ R.s = &l->tail;
+ movp();
+}
+OP(slicea)
+{
+ Type *t;
+ Heap *h;
+ Array *at, *ss, *ds;
+ int v, n, start;
+
+ v = W(m);
+ start = W(s);
+ n = v - start;
+ ds = A(d);
+
+ if(ds == H) {
+ if(n == 0)
+ return;
+ error(exNilref);
+ }
+ if(n < 0 || (ulong)start > ds->len || (ulong)v > ds->len)
+ error(exBounds);
+
+ t = ds->t;
+ h = heap(&Tarray);
+ ss = H2D(Array*, h);
+ ss->len = n;
+ ss->data = ds->data + start*t->size;
+ ss->t = t;
+ t->ref++;
+
+ if(ds->root != H) { /* slicing a slice */
+ ds = ds->root;
+ h = D2H(ds);
+ h->ref++;
+ at = A(d);
+ A(d) = ss;
+ ss->root = ds;
+ destroy(at);
+ }
+ else {
+ h = D2H(ds);
+ ss->root = ds;
+ A(d) = ss;
+ }
+ Setmark(h);
+}
+OP(slicela)
+{
+ Type *t;
+ int l, dl;
+ Array *ss, *ds;
+ uchar *sp, *dp, *ep;
+
+ ss = A(s);
+ dl = W(m);
+ ds = A(d);
+ if(ss == H)
+ return;
+ if(ds == H)
+ error(exNilref);
+ if(dl < 0 || dl+ss->len > ds->len)
+ error(exBounds);
+
+ t = ds->t;
+ if(t->np == 0) {
+ memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+ return;
+ }
+ sp = ss->data;
+ dp = ds->data+dl*t->size;
+
+ if(dp > sp) {
+ l = ss->len * t->size;
+ sp = ss->data + l;
+ ep = dp + l;
+ while(ep > dp) {
+ ep -= t->size;
+ sp -= t->size;
+ incmem(sp, t);
+ if (t->np)
+ freeptrs(ep, t);
+ }
+ }
+ else {
+ ep = dp + ss->len*t->size;
+ while(dp < ep) {
+ incmem(sp, t);
+ if (t->np)
+ freeptrs(dp, t);
+ dp += t->size;
+ sp += t->size;
+ }
+ }
+ memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+}
+OP(alt)
+{
+ R.t = 0;
+ xecalt(1);
+}
+OP(nbalt)
+{
+ xecalt(0);
+}
+OP(tcmp)
+{
+ void *s, *d;
+
+ s = T(s);
+ d = T(d);
+ if(s != H && (d == H || D2H(s)->t != D2H(d)->t))
+ error(exTcheck);
+}
+OP(eclr)
+{
+ /* spare slot */
+}
+OP(badop)
+{
+ error(exOp);
+}
+OP(iraise)
+{
+ void *v;
+ Heap *h;
+ Prog *p;
+
+ p = currun();
+ v = T(s);
+ if(v == H)
+ error(exNilref);
+ p->exval = v;
+ h = D2H(v);
+ h->ref++;
+ if(h->t == &Tstring)
+ error(string2c((String*)v));
+ else
+ error(string2c(*(String**)v));
+}
+OP(mulx)
+{
+ WORD p;
+ LONG r;
+
+ p = Dtmp;
+ r = (LONG)W(m)*(LONG)W(s);
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ W(d) = (WORD)r;
+}
+OP(divx)
+{
+ WORD p;
+ LONG s;
+
+ p = Dtmp;
+ s = (LONG)W(m);
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)W(s);
+ W(d) = (WORD)s;
+}
+OP(cvtxx)
+{
+ WORD p;
+ LONG r;
+
+ p = W(m);
+ r = (LONG)W(s);
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ W(d) = (WORD)r;
+}
+OP(mulx0)
+{
+ WORD x, y, p, a;
+ LONG r;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ a = Stmp;
+ if(x == 0 || y == 0){
+ W(d) = 0;
+ return;
+ }
+ r = (LONG)x*(LONG)y;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(divx0)
+{
+ WORD x, y, p, b;
+ LONG s;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ b = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ s = (LONG)b*(LONG)x;
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)y;
+ W(d) = (WORD)s;
+}
+OP(cvtxx0)
+{
+ WORD x, p, a;
+ LONG r;
+
+ x = W(s);
+ p = W(m);
+ a = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ r = (LONG)x;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(mulx1)
+{
+ WORD x, y, p, a, v;
+ int vnz, wnz;
+ LONG w, r;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ a = Stmp;
+ if(x == 0 || y == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = a-1;
+ if(x >= 0 && y < 0 || x < 0 && y >= 0)
+ v = -v;
+ }
+ if(wnz){
+ if((!vnz && (x > 0 && y < 0 || x < 0 && y > 0)) ||
+ (vnz && (x > 0 && y > 0 || x < 0 && y < 0)))
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ r = (LONG)x*(LONG)y + w;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r += (LONG)v;
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(divx1)
+{
+ WORD x, y, p, b, v;
+ int vnz, wnz;
+ LONG w, s;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ b = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = 1;
+ if(x >= 0 && y < 0 || x < 0 && y >= 0)
+ v = -v;
+ }
+ if(wnz){
+ if(x <= 0)
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ s = (LONG)b*(LONG)x + w;
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)y;
+ W(d) = (WORD)s + v;
+}
+OP(cvtxx1)
+{
+ WORD x, p, a, v;
+ int vnz, wnz;
+ LONG w, r;
+
+ x = W(s);
+ p = W(m);
+ a = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = a-1;
+ if(x < 0)
+ v = -v;
+ }
+ if(wnz){
+ if(!vnz && x < 0 || vnz && x > 0)
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ r = (LONG)x + w;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r += (LONG)v;
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+/*
+OP(cvtxx)
+{
+ REAL v;
+
+ v = (REAL)W(s)*F(m);
+ v = v < 0 ? v-0.5: v+0.5;
+ W(d) = (WORD)v;
+}
+*/
+OP(cvtfx)
+{
+ REAL v;
+
+ v = F(s)*F(m);
+ v = v < 0 ? v-0.5: v+0.5;
+ W(d) = (WORD)v;
+}
+OP(cvtxf)
+{
+ F(d) = (REAL)W(s)*F(m);
+}
+
+OP(self)
+{
+ Modlink *ml, **mp, *t;
+
+ ml = R.M;
+ D2H(ml)->ref++;
+ mp = R.d;
+ t = *mp;
+ *mp = ml;
+ destroy(t);
+}
+
+void
+destroystack(REG *reg)
+{
+ Type *t;
+ Frame *f, *fp;
+ Modlink *m;
+ Stkext *sx;
+ uchar *ex;
+
+ ex = reg->EX;
+ reg->EX = nil;
+ while(ex != nil) {
+ sx = (Stkext*)ex;
+ fp = sx->reg.tos.fr;
+ do {
+ f = (Frame*)reg->FP;
+ if(f == nil)
+ break;
+ reg->FP = f->fp;
+ t = f->t;
+ if(t == nil)
+ t = sx->reg.TR;
+ m = f->mr;
+ if (t->np)
+ freeptrs(f, t);
+ if(m != nil) {
+ destroy(reg->M);
+ reg->M = m;
+ }
+ } while(f != fp);
+ ex = sx->reg.EX;
+ free(sx);
+ }
+ destroy(reg->M);
+ reg->M = H; /* for devprof */
+}
+
+Prog*
+isave(void)
+{
+ Prog *p;
+
+ p = delrun(Prelease);
+ p->R = R;
+ return p;
+}
+
+void
+irestore(Prog *p)
+{
+ R = p->R;
+ R.IC = 1;
+}
+
+void
+movtmp(void) /* Used by send & receive */
+{
+ Type *t;
+
+ t = (Type*)W(m);
+
+ incmem(R.s, t);
+ if (t->np)
+ freeptrs(R.d, t);
+ memmove(R.d, R.s, t->size);
+}
+
+extern OP(cvtca);
+extern OP(cvtac);
+extern OP(cvtwc);
+extern OP(cvtcw);
+extern OP(cvtfc);
+extern OP(cvtcf);
+extern OP(insc);
+extern OP(indc);
+extern OP(addc);
+extern OP(lenc);
+extern OP(slicec);
+extern OP(cvtlc);
+
+#include "optab.h"
+
+void
+opinit(void)
+{
+ int i;
+
+ for(i = 0; i < 256; i++)
+ if(optab[i] == nil)
+ optab[i] = badop;
+}
+
+void
+xec(Prog *p)
+{
+ int op;
+
+ R = p->R;
+ R.MP = R.M->MP;
+ R.IC = p->quanta;
+
+ if(p->kill != nil) {
+ char *m;
+ m = p->kill;
+ p->kill = nil;
+ error(m);
+ }
+
+// print("%lux %lux %lux %lux %lux\n", (ulong)&R, R.xpc, R.FP, R.MP, R.PC);
+
+ if(R.M->compiled)
+ comvec();
+ else do {
+ dec[R.PC->add]();
+ op = R.PC->op;
+ R.PC++;
+ optab[op]();
+ } while(--R.IC != 0);
+
+ p->R = R;
+}