diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libinterp | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libinterp')
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; +} |
