diff options
| author | bhgv <bhgv.empire@gmail.com> | 2018-03-01 16:54:45 +0200 |
|---|---|---|
| committer | bhgv <bhgv.empire@gmail.com> | 2018-03-01 16:54:45 +0200 |
| commit | b786f20bbab5a59046aa78a2c6c2a11536497202 (patch) | |
| tree | 0851ecdec889eb9b7ba3751cc04d4f0b474e4a9e /libinterp | |
inferno-os tree was separated from the inferno-os-android (separated from the Android driver)
Diffstat (limited to 'libinterp')
64 files changed, 41202 insertions, 0 deletions
diff --git a/libinterp/NOTICE b/libinterp/NOTICE new file mode 100644 index 0000000..1986db1 --- /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-2009 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 0000000..3e346fa --- /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 0000000..75749e1 --- /dev/null +++ b/libinterp/alt.c @@ -0,0 +1,294 @@ +#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 ulong xrand = 0x20342; + + 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*1103515245 + 12345; + altcomm(a, (xrand>>8)%nrdy); + altdone(a, p, nil, -1); +} diff --git a/libinterp/comp-386.c b/libinterp/comp-386.c new file mode 100644 index 0000000..21a1271 --- /dev/null +++ b/libinterp/comp-386.c @@ -0,0 +1,1991 @@ +#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, sizeof(Rune)==4? 10: 11); + gen2(Oneg, (3<<6)|(3<<3)|RTA); + gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */ + gen2(0x73, 0xee); /* JNB */ + if(sizeof(Rune) == 4){ + gen2(Oldw, (1<<6)|(0<<3)|4); + gen2((2<<6)|(RBX<<3)|RAX, O(String, data)); + }else{ + 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)); + if(sizeof(Rune) == 4){ + gen2(Ojmpb, 4); + gen2(Oldw, (1<<6)|(0<<3)|4); /* movl 12(AX)(RBX*4), RAX */ + gen2((2<<6)|(RBX<<3)|RAX, O(String, data)); + }else{ + gen2(Ojmpb, 5); + genb(0x0f); + gen2(Omovzxw, (1<<6)|(0<<3)|4); /* movzwx 12(AX)(RBX*2), 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); + + segflush(comvec, 32); +} + +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); + + segflush(t->initialize, 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; + segflush(base, n*sizeof(base)); + return 1; +bad: + free(patch); + free(tinit); + free(tmp); + free(base); + return 0; +} + diff --git a/libinterp/comp-arm.c b/libinterp/comp-arm.c new file mode 100644 index 0000000..a3b1024 --- /dev/null +++ b/libinterp/comp-arm.c @@ -0,0 +1,2280 @@ +#include "lib9.h" +#include "isa.h" +#include "interp.h" +#include "raise.h" + +/* + * to do: + * eliminate litpool? + * eliminate long constants in comi/comd + * enable and check inline FP code (not much point with fpemu) + */ + +#define RESCHED 1 /* check for interpreter reschedule */ +#define SOFTFP 1 + +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, + + Blo = 0, /* offset of low order word in big */ + Bhi = 4, /* offset of high order word in big */ + + Lg2Rune = 2, + + 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 FITS12(v) ((ulong)(v)<BITS(12)) +#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, nullity)) + +/* 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)) +#define BCKR(i, rb) (CMPI(AL, rb, 0, 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)) { + if(disp != 0 || rm != r) + 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 +nullity(void) +{ + /* mem(Stw, O(REG,FP), RREG, RFP); */ + error(exNilref); +} + +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, Bhi, RA1, RA2); + mem(Ldw, Bhi, 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, Blo, RA3, RA0); + mem(Ldw, Blo, 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(!SOFTFP){ + 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, Blo, RA0, RA1); // ls + mem(Ldw, Blo, RA3, RA2); + DP(AL, op, RA2, RA2, 0, RA1) | SBIT; // ls: RA2 = RA2 op RA1 + mem(Ldw, Bhi, RA0, RA1); + mem(Ldw, Bhi, 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, Blo, RA3, RA2); + mem(Stw, Bhi, RA3, RA0); +} + +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(!SOFTFP){ + 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); + if(OA(List,data) != 0) + 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 || !FITS12((short)i->reg<<Lg2Rune) || immrot((short)i->reg) == 0){ + mid(i, Ldw, RA2); // RA2 = i + imm = 0; + } + mem(Ldw, O(String,len),RA1, RA0); // len<0 => index Runes, otherwise bytes + if(bflag){ + DPI(AL, Orr, RA0, RA3, 0, 0); + DPI(LT, Rsb, RA3, RA3, 0, 0); + if(imm) + BCKR(immrot((short)i->reg), RA3); + else + BCK(RA2, RA3); + } + DPI(AL, Add, RA1, RA1, 0, O(String,data)); + CMPI(AL, RA0, 0, 0, 0); + if(imm){ + LDB(GE, RA1, RA3, i->reg); + LDW(LT, RA1, RA3, (short)i->reg<<Lg2Rune); + } else { + LDRB(GE, RA1, RA3, 0, RA2); + DP(LT, Mov, 0, RA2, (Lg2Rune<<3), RA2); + LDRW(LT, RA1, RA3, 0, RA2); + } + opwst(i, Stw, RA3); +//if(pass){print("%D\n", i); das(s, code-s);} + break; + case IINDL: + case IINDF: + case IINDW: + case IINDB: + opwld(i, Ldw, RA0); /* a */ + NOTNIL(RA0); + if(bflag) + mem(Ldw, O(Array, len), RA0, RA2); + 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) && (imm = immrot(i->d.imm)) != 0) { + if(bflag) + BCKR(imm, RA2); + if(i->d.imm != 0) + DPI(AL, Add, RA0, RA0, 0, 0) | immrot(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); +//if(pass){print("%D\n", i); das(s, code-s);} + 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); +//if(pass){print("%D\n", i); das(s, code-s);} + 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, RA1, Blo); + STW(AL, RA2, RA0, Bhi); + break; + case ICVTLW: + opwld(i, Lea, RA0); + mem(Ldw, Blo, 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(SOFTFP){ + /* software fp */ + USED(r); + 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(SOFTFP){ + 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(SOFTFP){ + 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(SOFTFP){ + 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: + /* should do better */ + punt(i, SRCOP|DSTOP|THREOP, optab[i->op]); + break; + case ISHRL: + /* should do better */ + 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); +} + +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 0000000..cd15c72 --- /dev/null +++ b/libinterp/comp-mips.c @@ -0,0 +1,1962 @@ +#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)) + +#ifndef HIOFFSET +#define HIOFFSET 0 /* big endian */ +#endif + +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, + + Bhi = HIOFFSET, + Blo = Bhi ^ 4, + + 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, Bhi,Ri, Ro1); + IRR(Olw, Bhi,Rj, Ro2); + IRR(Olw, Blo,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, Blo,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, Blo,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, Bhi,Ro3, Ro1); + if(c >= 32) { + if((i->add&ARM) != AXNON) + op3(i, Olea, Ro3, 0); + else + delay(); + SRR(Osra, 31, Ro1, Ro2); + IRR(Osw, Bhi,Ro3, Ro2); + if(c >= 64) { + IRR(Osw, Blo,Ro3, Ro2); + return; + } + if(c > 32) + SRR(Osra, c-32, Ro1, Ro1); + IRR(Osw, Blo,Ro3, Ro1); + return; + } + IRR(Olw, Blo,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, Blo,Ro3, Ro2); + IRR(Osw, Bhi,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, Bhi,Ro3, Rzero); + IRR(Osw, Blo,Ro3, Rzero); + return; + } + op2(i, Olea, Ro3, 1); + if(c >= 32) { + IRR(Olw, Blo,Ro3, Ro1); + if((i->add&ARM) != AXNON) + op3(i, Olea, Ro3, 1); + IRR(Osw, Blo,Ro3, Rzero); + if(c > 32) + SRR(Osll, c-32, Ro1, Ro1); + IRR(Osw, Bhi,Ro3, Ro1); + return; + } + IRR(Olw, Blo,Ro3, Ro2); + IRR(Olw, Bhi,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, Blo,Ro3, Ro2); + IRR(Osw, Bhi,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, Blo,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, Blo,Ro2, Ro1); + IRR(Osw, Bhi,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, Bhi,Ro1, Rf2+1); + IRR(Olf, Blo,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, Bhi,Ro2, Rf2+1); + IRR(Osf, Blo,Ro2, Rf2); + break; + case INEGF: + op1(i, Olea, Ro1, 1); + IRR(Olf, Bhi,Ro1, Rf1+1); + IRR(Olf, Blo,Ro1, Rf1); + op3(i, Olea, Ro2, 1); + FRRR(Onegf, 0, Rf1,Rf2); + IRR(Osf, Bhi,Ro2, Rf2+1); + IRR(Osf, Blo,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, Blo,Ro1, Rj); /* ls */ + IRR(Olw, Blo,Ro3, Ro2); + IRR(Olw, Bhi,Ro1, Ri); /* ms */ + IRR(Olw, Bhi,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, Bhi,Ro3, Ro1); + IRR(Osw, Blo,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, Bhi,Ro1, Rf1+1); + IRR(Olf, Blo,Ro1, Rf1); + IRR(Olf, Bhi,Ro2, Rf2+1); + IRR(Olf, Blo,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, Bhi,Ro1, Rf2+1); + IRR(Osf, Blo,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 0000000..a53b0bf --- /dev/null +++ b/libinterp/comp-power.c @@ -0,0 +1,2261 @@ +#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), + + Lg2Rune = sizeof(Rune)==4? 2: 1, + 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, Lg2Rune); + if(sizeof(Rune) == 4) + ARRR(Olwz, Ro3, Ro1, Ro2); + else + ARRR(Olhzx, Ro3, Ro1, Ro2); + } else + mem(Olwz, (short)i->reg<<Lg2Rune, Ro1, Ro3); /* BUG: TO DO: 16-bit signed displacement */ + 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-sparc.c b/libinterp/comp-sparc.c new file mode 100644 index 0000000..f6ca2aa --- /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 0000000..0ffb0f1 --- /dev/null +++ b/libinterp/comp-spim.c @@ -0,0 +1,2 @@ +#define HIOFFSET 4 /* byte offset of high-order word in little-endian vlongs */ +#include "comp-mips.c" diff --git a/libinterp/conv.c b/libinterp/conv.c new file mode 100644 index 0000000..b5a8e94 --- /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/crypt.c b/libinterp/crypt.c new file mode 100644 index 0000000..751be77 --- /dev/null +++ b/libinterp/crypt.c @@ -0,0 +1,1349 @@ +#include "lib9.h" +#include "kernel.h" +#include <isa.h> +#include "interp.h" +#include "runt.h" +#include "cryptfoos.h" +#include "cryptmod.h" +#include <mp.h> +#include <libsec.h> +#include "pool.h" +#include "raise.h" +#include "ipint.h" + +#define MPX(x) checkIPint((void*)(x)) + +static Type* TDigestState; +static Type* TAESstate; +static Type* TDESstate; +static Type* TIDEAstate; +static Type* TBFstate; +static Type* TRC4state; + +static Type* TSKdsa; +static Type* TPKdsa; +static Type* TPKsigdsa; +static Type* TSKeg; +static Type* TPKeg; +static Type* TPKsigeg; +static Type* TSKrsa; +static Type* TPKrsa; +static Type* TPKsigrsa; + +static uchar DigestStatemap[] = Crypt_DigestState_map; +static uchar AESstatemap[] = Crypt_AESstate_map; +static uchar DESstatemap[] = Crypt_DESstate_map; +static uchar IDEAstatemap[] = Crypt_IDEAstate_map; +static uchar BFstatemap[] = Crypt_BFstate_map; +static uchar RC4statemap[] = Crypt_RC4state_map; + +static uchar DSAskmap[] = Crypt_SK_DSA_map; +static uchar DSApkmap[] = Crypt_PK_DSA_map; +static uchar DSAsigmap[] = Crypt_PKsig_DSA_map; +static uchar EGskmap[] = Crypt_SK_Elgamal_map; +static uchar EGpkmap[] = Crypt_PK_Elgamal_map; +static uchar EGsigmap[] = Crypt_PKsig_Elgamal_map; +static uchar RSAskmap[] = Crypt_SK_RSA_map; +static uchar RSApkmap[] = Crypt_PK_RSA_map; +static uchar RSAsigmap[] = Crypt_PKsig_RSA_map; + +static char exBadBsize[] = "data not multiple of block size"; +static char exBadKey[] = "bad encryption key"; +static char exBadDigest[] = "bad digest value"; +static char exBadIvec[] = "bad ivec"; +static char exBadState[] = "bad encryption state"; + +/* + * these structures reveal the C state of Limbo adts in crypt.m + */ + +typedef struct XDigestState XDigestState; +typedef struct XAESstate XAESstate; +typedef struct XDESstate XDESstate; +typedef struct XIDEAstate XIDEAstate; +typedef struct XBFstate XBFstate; +typedef struct XRC4state XRC4state; + +/* digest state */ +struct XDigestState +{ + Crypt_DigestState x; + DigestState state; +}; + +/* AES state */ +struct XAESstate +{ + Crypt_AESstate x; + AESstate state; +}; + +/* DES state */ +struct XDESstate +{ + Crypt_DESstate x; + DESstate state; +}; + +/* IDEA state */ +struct XIDEAstate +{ + Crypt_IDEAstate x; + IDEAstate state; +}; + +/* BF state */ +struct XBFstate +{ + Crypt_BFstate x; + BFstate state; +}; + +/* RC4 state */ +struct XRC4state +{ + Crypt_RC4state x; + RC4state state; +}; + +static Crypt_PK* +newPK(Type *t, int pick) +{ + Heap *h; + Crypt_PK *sk; + + h = heap(t); + sk = H2D(Crypt_PK*, h); + sk->pick = pick; + return sk; +} + +static Crypt_SK* +newSK(Crypt_SK** ret, Type *t, int pick) +{ + Heap *h; + Crypt_SK *sk; + + h = heap(t); + sk = H2D(Crypt_SK*, h); + sk->pick = pick; + if(ret != nil) + *ret = sk; + switch(pick){ + case Crypt_PK_RSA: + sk->u.RSA.pk = newPK(TPKrsa, Crypt_PK_RSA); + break; + case Crypt_PK_Elgamal: + sk->u.Elgamal.pk = newPK(TPKeg, Crypt_PK_Elgamal); + break; + case Crypt_PK_DSA: + sk->u.DSA.pk = newPK(TPKdsa, Crypt_PK_DSA); + break; + default: + error(exType); + } + return sk; +} + +static Crypt_PKsig* +newPKsig(Type *t, int pick) +{ + Heap *h; + Crypt_PKsig *s; + + h = heap(t); + s = H2D(Crypt_PKsig*, h); + s->pick = pick; + return s; +} + +static IPints_IPint* +ipcopymp(mpint* b) +{ + if(b == nil) + return H; + return newIPint(mpcopy(b)); +} + +/* + * digests + */ +void +DigestState_copy(void *fp) +{ + F_DigestState_copy *f; + Heap *h; + XDigestState *ds, *ods; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->d != H){ + ods = checktype(f->d, TDigestState, "DigestState", 0); + h = heap(TDigestState); + ds = H2D(XDigestState*, h); + memmove(&ds->state, &ods->state, sizeof(ds->state)); + *f->ret = (Crypt_DigestState*)ds; + } +} + +static Crypt_DigestState* +crypt_digest_x(Array *buf, int n, Array *digest, int dlen, Crypt_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) + error(exInval); + cbuf = nil; + } + + if(digest != H){ + if(digest->len < dlen) + error(exBadDigest); + cdigest = digest->data; + } else + cdigest = nil; + + if(state == H){ + h = heap(TDigestState); + ds = H2D(XDigestState*, h); + memset(&ds->state, 0, sizeof(ds->state)); + } else + ds = checktype(state, TDigestState, "DigestState", 1); + + (*fn)(cbuf, n, cdigest, &ds->state); + + return (Crypt_DigestState*)ds; +} + +void +Crypt_sha1(void *fp) +{ + F_Crypt_sha1 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1); +} + +void +Crypt_sha224(void *fp) +{ + F_Crypt_sha224 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224); +} + +void +Crypt_sha256(void *fp) +{ + F_Crypt_sha256 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256); +} + +void +Crypt_sha384(void *fp) +{ + F_Crypt_sha384 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384); +} + +void +Crypt_sha512(void *fp) +{ + F_Crypt_sha512 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512); +} + +void +Crypt_md5(void *fp) +{ + F_Crypt_md5 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5); +} + +void +Crypt_md4(void *fp) +{ + F_Crypt_md4 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4); +} + +static Crypt_DigestState* +crypt_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Crypt_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) + error(exInval); + cdata = nil; + } + + if(key == H || key->len > 64) + error(exBadKey); + + if(digest != H){ + if(digest->len < dlen) + error(exBadDigest); + cdigest = digest->data; + } else + cdigest = nil; + + if(state == H){ + h = heap(TDigestState); + ds = H2D(XDigestState*, h); + memset(&ds->state, 0, sizeof(ds->state)); + } else + ds = checktype(state, TDigestState, "DigestState", 1); + + (*fn)(cdata, n, key->data, key->len, cdigest, &ds->state); + + return (Crypt_DigestState*)ds; +} + +void +Crypt_hmac_sha1(void *fp) +{ + F_Crypt_hmac_sha1 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + *f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1); +} + +void +Crypt_hmac_md5(void *fp) +{ + F_Crypt_hmac_md5 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + *f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5); +} + +void +Crypt_dhparams(void *fp) +{ + F_Crypt_dhparams *f; + mpint *p, *alpha; + void *v; + + f = fp; + v = f->ret->t0; + f->ret->t0 = H; + destroy(v); + v = f->ret->t1; + f->ret->t1 = H; + destroy(v); + + p = mpnew(0); + alpha = mpnew(0); + release(); + if(f->nbits == 1024) + DSAprimes(alpha, p, nil); + else + gensafeprime(p, alpha, f->nbits, 0); + acquire(); + f->ret->t0 = newIPint(alpha); + f->ret->t1 = newIPint(p); +} + +void +cryptmodinit(void) +{ + ipintsmodinit(); /* TIPint */ + + 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)); + TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap, sizeof(BFstatemap)); + TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap, sizeof(RC4statemap)); + + TSKdsa = dtype(freeheap, Crypt_SK_DSA_size, DSAskmap, sizeof(DSAskmap)); + TPKdsa = dtype(freeheap, Crypt_PK_DSA_size, DSApkmap, sizeof(DSApkmap)); + TPKsigdsa = dtype(freeheap, Crypt_PKsig_DSA_size, DSAsigmap, sizeof(DSAsigmap)); + TSKeg = dtype(freeheap, Crypt_SK_Elgamal_size, EGskmap, sizeof(EGskmap)); + TPKeg = dtype(freeheap, Crypt_PK_Elgamal_size, EGpkmap, sizeof(EGpkmap)); + TPKsigeg = dtype(freeheap, Crypt_PKsig_Elgamal_size, EGsigmap, sizeof(EGsigmap)); + TSKrsa = dtype(freeheap, Crypt_SK_RSA_size, RSAskmap, sizeof(RSAskmap)); + TPKrsa = dtype(freeheap, Crypt_PK_RSA_size, RSApkmap, sizeof(RSApkmap)); + TPKsigrsa = dtype(freeheap, Crypt_PKsig_RSA_size, RSAsigmap, sizeof(RSAsigmap)); + + builtinmod("$Crypt", Cryptmodtab, Cryptmodlen); +} + +void +Crypt_dessetup(void *fp) +{ + F_Crypt_dessetup *f; + Heap *h; + XDESstate *ds; + uchar *ivec; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->key == H) + error(exNilref); + if(f->key->len < 8) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len < 8) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + h = heap(TDESstate); + ds = H2D(XDESstate*, h); + setupDESstate(&ds->state, f->key->data, ivec); + + *f->ret = (Crypt_DESstate*)ds; +} + +void +Crypt_desecb(void *fp) +{ + F_Crypt_desecb *f; + XDESstate *ds; + int i; + uchar *p; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + ds = checktype(f->state, TDESstate, exBadState, 0); + p = f->buf->data; + + for(i = 8; i <= f->n; i += 8, p += 8) + block_cipher(ds->state.expanded, p, f->direction); +} + +void +Crypt_descbc(void *fp) +{ + F_Crypt_descbc *f; + XDESstate *ds; + uchar *p, *ep, *ip, *p2, *eip; + uchar tmp[8]; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + ds = checktype(f->state, TDESstate, exBadState, 0); + 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 +Crypt_ideasetup(void *fp) +{ + F_Crypt_ideasetup *f; + Heap *h; + XIDEAstate *is; + uchar *ivec; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->key == H) + error(exNilref); + if(f->key->len < 16) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len < 8) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + h = heap(TIDEAstate); + is = H2D(XIDEAstate*, h); + + setupIDEAstate(&is->state, f->key->data, ivec); + + *f->ret = (Crypt_IDEAstate*)is; +} + +void +Crypt_ideaecb(void *fp) +{ + F_Crypt_ideaecb *f; + XIDEAstate *is; + int i; + uchar *p; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + is = checktype(f->state, TIDEAstate, exBadState, 0); + p = f->buf->data; + + for(i = 8; i <= f->n; i += 8, p += 8) + idea_cipher(is->state.edkey, p, f->direction); +} + +void +Crypt_ideacbc(void *fp) +{ + F_Crypt_ideacbc *f; + XIDEAstate *is; + uchar *p, *ep, *ip, *p2, *eip; + uchar tmp[8]; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + is = checktype(f->state, TIDEAstate, exBadState, 0); + 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 +Crypt_aessetup(void *fp) +{ + F_Crypt_aessetup *f; + Heap *h; + XAESstate *is; + uchar *ivec; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->key == H) + error(exNilref); + if(f->key->len != 16 && f->key->len != 24 && f->key->len != 32) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len < AESbsize) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + h = heap(TAESstate); + is = H2D(XAESstate*, h); + + setupAESstate(&is->state, f->key->data, f->key->len, ivec); + + *f->ret = (Crypt_AESstate*)is; +} + +void +Crypt_aescbc(void *fp) +{ + F_Crypt_aescbc *f; + XAESstate *is; + uchar *p; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + + is = checktype(f->state, TAESstate, exBadState, 0); + p = f->buf->data; + + if(f->direction == 0) + aesCBCencrypt(p, f->n, &is->state); + else + aesCBCdecrypt(p, f->n, &is->state); +} + +void +Crypt_blowfishsetup(void *fp) +{ + F_Crypt_blowfishsetup *f; + Heap *h; + XBFstate *is; + uchar *ivec; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->key == H) + error(exNilref); + if(f->key->len <= 0) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len != BFbsize) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + h = heap(TBFstate); + is = H2D(XBFstate*, h); + + setupBFstate(&is->state, f->key->data, f->key->len, ivec); + + *f->ret = (Crypt_BFstate*)is; +} + +void +Crypt_blowfishcbc(void *fp) +{ + F_Crypt_blowfishcbc *f; + XBFstate *is; + uchar *p; + + f = fp; + + if(f->state == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + is = checktype(f->state, TBFstate, exBadState, 0); + p = f->buf->data; + + if(f->direction == 0) + bfCBCencrypt(p, f->n, &is->state); + else + bfCBCdecrypt(p, f->n, &is->state); +} + +void +Crypt_rc4setup(void *fp) +{ + F_Crypt_rc4setup *f; + Heap *h; + XRC4state *is; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->seed == H) + error(exNilref); + + h = heap(TRC4state); + is = H2D(XRC4state*, h); + + setupRC4state(&is->state, f->seed->data, f->seed->len); + + *f->ret = (Crypt_RC4state*)is; +} + +void +Crypt_rc4(void *fp) +{ + F_Crypt_rc4 *f; + XRC4state *is; + uchar *p; + + f = fp; + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + is = checktype(f->state, TRC4state, exBadState, 0); + p = f->buf->data; + rc4(&is->state, p, f->n); +} + +void +Crypt_rc4skip(void *fp) +{ + F_Crypt_rc4skip *f; + XRC4state *is; + + f = fp; + is = checktype(f->state, TRC4state, exBadState, 0); + rc4skip(&is->state, f->n); +} + +void +Crypt_rc4back(void *fp) +{ + F_Crypt_rc4back *f; + XRC4state *is; + + f = fp; + is = checktype(f->state, TRC4state, exBadState, 0); + rc4back(&is->state, f->n); +} + +/* + * public/secret keys, signing and verifying + */ + +/* + * DSA + */ + +static void +dsapk2pub(DSApub* p, Crypt_PK* pk) +{ + if(pk == H) + error(exNilref); + if(pk->pick != Crypt_PK_DSA) + error(exType); + p->p = MPX(pk->u.DSA.p); + p->q = MPX(pk->u.DSA.q); + p->alpha = MPX(pk->u.DSA.alpha); + p->key = MPX(pk->u.DSA.key); +} + +static void +dsask2priv(DSApriv* p, Crypt_SK* sk) +{ + if(sk == H) + error(exNilref); + if(sk->pick != Crypt_SK_DSA) + error(exType); + dsapk2pub(&p->pub, sk->u.DSA.pk); + p->secret = MPX(sk->u.DSA.secret); +} + +static void +dsapriv2sk(Crypt_SK* sk, DSApriv* p) +{ + Crypt_PK *pk; + + pk = sk->u.DSA.pk; + pk->u.DSA.p = ipcopymp(p->pub.p); + pk->u.DSA.q = ipcopymp(p->pub.q); + pk->u.DSA.alpha = ipcopymp(p->pub.alpha); + pk->u.DSA.key = ipcopymp(p->pub.key); + sk->u.DSA.secret = ipcopymp(p->secret); +} + +static void +dsaxgen(Crypt_SK* sk, DSApub* oldpk) +{ + DSApriv *p; + + release(); + p = dsagen(oldpk); + acquire(); + dsapriv2sk(sk, p); + dsaprivfree(p); +} + +void +Crypt_dsagen(void *fp) +{ + F_Crypt_dsagen *f; + Crypt_SK *sk; + DSApub pub, *oldpk; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA); + oldpk = nil; + if(f->oldpk != H && f->oldpk->pick == Crypt_PK_DSA){ + dsapk2pub(&pub, f->oldpk); + oldpk = &pub; + } + dsaxgen(sk, oldpk); +} + +/* + * Elgamal + */ + +static void +egpk2pub(EGpub* p, Crypt_PK* pk) +{ + if(pk == H) + error(exNilref); + if(pk->pick != Crypt_PK_Elgamal) + error(exType); + p->p = MPX(pk->u.Elgamal.p); + p->alpha = MPX(pk->u.Elgamal.alpha); + p->key = MPX(pk->u.Elgamal.key); +} + +static void +egsk2priv(EGpriv* p, Crypt_SK* sk) +{ + if(sk == H) + error(exNilref); + if(sk->pick != Crypt_SK_Elgamal) + error(exType); + egpk2pub(&p->pub, sk->u.Elgamal.pk); + p->secret = MPX(sk->u.Elgamal.secret); +} + +static void +egpriv2sk(Crypt_SK* sk, EGpriv* p) +{ + Crypt_PK* pk; + + pk = sk->u.Elgamal.pk; + pk->u.Elgamal.p = ipcopymp(p->pub.p); + pk->u.Elgamal.alpha = ipcopymp(p->pub.alpha); + pk->u.Elgamal.key = ipcopymp(p->pub.key); + sk->u.Elgamal.secret = ipcopymp(p->secret); +} + +static void +egxgen(Crypt_SK* sk, int nlen, int nrep) +{ + EGpriv *p; + + release(); + for(;;){ + p = eggen(nlen, nrep); + if(mpsignif(p->pub.p) == nlen) + break; + egprivfree(p); + } + acquire(); + egpriv2sk(sk, p); + egprivfree(p); +} + + +void +Crypt_eggen(void *fp) +{ + F_Crypt_eggen *f; + Crypt_SK *sk; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal); + egxgen(sk, f->nlen, f->nrep); +} + +/* + * RSA + */ + +static void +rsapk2pub(RSApub* p, Crypt_PK* pk) +{ + if(pk == H) + error(exNilref); + if(pk->pick != Crypt_PK_RSA) + error(exType); + p->n = MPX(pk->u.RSA.n); + p->ek = MPX(pk->u.RSA.ek); +} + +static void +rsask2priv(RSApriv* p, Crypt_SK* sk) +{ + if(sk == H) + error(exNilref); + if(sk->pick != Crypt_SK_RSA) + error(exType); + rsapk2pub(&p->pub, sk->u.RSA.pk); + p->dk = MPX(sk->u.RSA.dk); + p->p = MPX(sk->u.RSA.p); + p->q = MPX(sk->u.RSA.q); + p->kp = MPX(sk->u.RSA.kp); + p->kq = MPX(sk->u.RSA.kq); + p->c2 = MPX(sk->u.RSA.c2); +} + +static void +rsapriv2sk(Crypt_SK* sk, RSApriv* p) +{ + Crypt_PK *pk; + + pk = sk->u.RSA.pk; + pk->u.RSA.n = ipcopymp(p->pub.n); + pk->u.RSA.ek = ipcopymp(p->pub.ek); + sk->u.RSA.dk = ipcopymp(p->dk); + sk->u.RSA.p = ipcopymp(p->p); + sk->u.RSA.q = ipcopymp(p->q); + sk->u.RSA.kp = ipcopymp(p->kp); + sk->u.RSA.kq = ipcopymp(p->kq); + sk->u.RSA.c2 = ipcopymp(p->c2); +} + +static void +rsaxgen(Crypt_SK *sk, int nlen, int elen, int nrep) +{ + RSApriv *p; + + release(); + for(;;){ + p = rsagen(nlen, elen, nrep); + if(mpsignif(p->pub.n) == nlen) + break; + rsaprivfree(p); + } + acquire(); + rsapriv2sk(sk, p); + rsaprivfree(p); +} + +void +Crypt_rsagen(void *fp) +{ + F_Crypt_rsagen *f; + Crypt_SK *sk; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA); + rsaxgen(sk, f->nlen, f->elen, f->nrep); +} + +void +Crypt_rsafill(void *fp) +{ + F_Crypt_rsafill *f; + Crypt_SK *sk; + RSApriv *p; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA); + release(); + p = rsafill(MPX(f->n), MPX(f->ek), MPX(f->dk), + MPX(f->p), MPX(f->q)); + acquire(); + if(p == nil) { + *f->ret = H; + destroy(sk); + }else{ + rsapriv2sk(sk, p); + rsaprivfree(p); + } +} + +void +Crypt_rsaencrypt(void *fp) +{ + F_Crypt_rsaencrypt *f; + RSApub p; + mpint *m, *o; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + rsapk2pub(&p, f->k); + m = MPX(f->m); + release(); + o = rsaencrypt(&p, m, nil); + acquire(); + *f->ret = newIPint(o); +} + +void +Crypt_rsadecrypt(void *fp) +{ + F_Crypt_rsadecrypt *f; + RSApriv p; + mpint *m, *o; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + rsask2priv(&p, f->k); + m = MPX(f->m); + release(); + o = rsadecrypt(&p, m, nil); + acquire(); + *f->ret = newIPint(o); +} + +/* + * generic key functions + */ + +void +Crypt_genSK(void *fp) +{ + F_Crypt_genSK *f; + Crypt_SK *sk; + char *sa; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + sa = string2c(f->algname); + if(strcmp(sa, "rsa") == 0){ + sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA); + rsaxgen(sk, f->length, 6, 0); + }else if(strcmp(sa, "dsa") == 0){ + sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA); + dsaxgen(sk, nil); + }else if(strcmp(sa, "elgamal") == 0){ + sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal); + egxgen(sk, f->length, 0); + } + /* genSK returns nil for unknown algorithm */ +} + +void +Crypt_genSKfromPK(void *fp) +{ + F_Crypt_genSKfromPK *f; + Crypt_SK *sk; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->pk == H) + error(exNilref); + switch(f->pk->pick){ + case Crypt_PK_RSA: { + RSApub p; + + rsapk2pub(&p, f->pk); + sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA); + rsaxgen(sk, mpsignif(p.n), mpsignif(p.ek), 0); + } + break; + case Crypt_PK_Elgamal: { + EGpub p; + + egpk2pub(&p, f->pk); + sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal); + egxgen(sk, mpsignif(p.p), 0); + } + break; + case Crypt_PK_DSA: { + DSApub p; + + dsapk2pub(&p, f->pk); + sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA); + dsaxgen(sk, &p); + } + break; + default: + /* shouldn't happen */ + error(exType); + } +} + +void +Crypt_sktopk(void *fp) +{ + F_Crypt_sktopk *f; + Crypt_PK *pk; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + if(f->sk == H) + error(exNilref); + switch(f->sk->pick){ + case Crypt_PK_RSA: + pk = f->sk->u.RSA.pk; + break; + case Crypt_PK_Elgamal: + pk = f->sk->u.Elgamal.pk; + break; + case Crypt_PK_DSA: + pk = f->sk->u.DSA.pk; + break; + default: + pk = H; + error(exType); + } + if(pk == H) + return; + D2H(pk)->ref++; + *f->ret = pk; +} + +void +Crypt_sign(void *fp) +{ + F_Crypt_sign *f; + Crypt_PKsig *sig; + mpint *m; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + if(f->m == H || f->sk == H) + error(exNilref); + m = MPX(f->m); + switch(f->sk->pick){ + case Crypt_SK_RSA: { + RSApriv p; + mpint *s; + + rsask2priv(&p, f->sk); + release(); + s = rsadecrypt(&p, m, nil); + acquire(); + sig = newPKsig(TPKsigrsa, Crypt_PKsig_RSA); + sig->u.RSA.n = newIPint(s); + } + break; + case Crypt_SK_Elgamal: { + EGpriv p; + EGsig *s; + + egsk2priv(&p, f->sk); + release(); + s = egsign(&p, m); + acquire(); + sig = newPKsig(TPKsigeg, Crypt_PKsig_Elgamal); + sig->u.Elgamal.r = ipcopymp(s->r); + sig->u.Elgamal.s = ipcopymp(s->s); + egsigfree(s); + } + break; + case Crypt_SK_DSA: { + DSApriv p; + DSAsig *s; + + dsask2priv(&p, f->sk); + m = MPX(f->m); + release(); + s = dsasign(&p, m); + acquire(); + sig = newPKsig(TPKsigdsa, Crypt_PKsig_DSA); + sig->u.DSA.r = ipcopymp(s->r); + sig->u.DSA.s = ipcopymp(s->s); + dsasigfree(s); + } + break; + default: + sig = H; + error(exType); + } + *f->ret = sig; +} + +void +Crypt_verify(void *fp) +{ + F_Crypt_verify *f; + mpint *m; + + f = fp; + *f->ret = 0; + if(f->sig == H || f->pk == H) + error(exNilref); + if(f->sig->pick != f->pk->pick) + return; /* key type and signature mismatch, doesn't validate */ + m = MPX(f->m); + switch(f->pk->pick){ + case Crypt_PK_RSA: { + RSApub p; + mpint *sig, *t; + + rsapk2pub(&p, f->pk); + sig = MPX(f->sig->u.RSA.n); + release(); + t = rsaencrypt(&p, sig, nil); + *f->ret = mpcmp(t, m) == 0; + mpfree(t); + acquire(); + } + break; + case Crypt_PK_Elgamal: { + EGpub p; + EGsig sig; + + egpk2pub(&p, f->pk); + sig.r = MPX(f->sig->u.Elgamal.r); + sig.s = MPX(f->sig->u.Elgamal.s); + release(); + *f->ret = egverify(&p, &sig, m) == 0; + acquire(); + } + break; + case Crypt_PK_DSA: { + DSApub p; + DSAsig sig; + + dsapk2pub(&p, f->pk); + sig.r = MPX(f->sig->u.DSA.r); + sig.s = MPX(f->sig->u.DSA.s); + release(); + *f->ret = dsaverify(&p, &sig, m) == 0; + acquire(); + } + break; + default: + error(exType); + } +} diff --git a/libinterp/cryptfoos.h b/libinterp/cryptfoos.h new file mode 100644 index 0000000..f385315 --- /dev/null +++ b/libinterp/cryptfoos.h @@ -0,0 +1,36 @@ +void Crypt_aescbc(void*); +void Crypt_aessetup(void*); +void Crypt_blowfishcbc(void*); +void Crypt_blowfishsetup(void*); +void DigestState_copy(void*); +void Crypt_descbc(void*); +void Crypt_desecb(void*); +void Crypt_dessetup(void*); +void Crypt_dhparams(void*); +void Crypt_dsagen(void*); +void Crypt_eggen(void*); +void Crypt_genSK(void*); +void Crypt_genSKfromPK(void*); +void Crypt_hmac_md5(void*); +void Crypt_hmac_sha1(void*); +void Crypt_ideacbc(void*); +void Crypt_ideaecb(void*); +void Crypt_ideasetup(void*); +void Crypt_md4(void*); +void Crypt_md5(void*); +void Crypt_rc4(void*); +void Crypt_rc4back(void*); +void Crypt_rc4setup(void*); +void Crypt_rc4skip(void*); +void Crypt_rsadecrypt(void*); +void Crypt_rsaencrypt(void*); +void Crypt_rsafill(void*); +void Crypt_rsagen(void*); +void Crypt_sha1(void*); +void Crypt_sha224(void*); +void Crypt_sha256(void*); +void Crypt_sha384(void*); +void Crypt_sha512(void*); +void Crypt_sign(void*); +void Crypt_sktopk(void*); +void Crypt_verify(void*); diff --git a/libinterp/cryptmod.h b/libinterp/cryptmod.h new file mode 100644 index 0000000..e0755e9 --- /dev/null +++ b/libinterp/cryptmod.h @@ -0,0 +1,41 @@ +typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab; +Runtab Cryptmodtab[]={ + "aescbc",0xac616ba,Crypt_aescbc,48,2,{0x0,0xc0,}, + "aessetup",0x44452583,Crypt_aessetup,40,2,{0x0,0xc0,}, + "blowfishcbc",0xac616ba,Crypt_blowfishcbc,48,2,{0x0,0xc0,}, + "blowfishsetup",0x44452583,Crypt_blowfishsetup,40,2,{0x0,0xc0,}, + "DigestState.copy",0x491fbd11,DigestState_copy,40,2,{0x0,0x80,}, + "descbc",0xac616ba,Crypt_descbc,48,2,{0x0,0xc0,}, + "desecb",0xac616ba,Crypt_desecb,48,2,{0x0,0xc0,}, + "dessetup",0x44452583,Crypt_dessetup,40,2,{0x0,0xc0,}, + "dhparams",0x6abb2418,Crypt_dhparams,40,0,{0}, + "dsagen",0xfca97ad3,Crypt_dsagen,40,2,{0x0,0x80,}, + "eggen",0x6e59448f,Crypt_eggen,40,0,{0}, + "genSK",0x5d82edbe,Crypt_genSK,40,2,{0x0,0x80,}, + "genSKfromPK",0x368c3183,Crypt_genSKfromPK,40,2,{0x0,0x80,}, + "hmac_md5",0xec9ac159,Crypt_hmac_md5,56,2,{0x0,0xb8,}, + "hmac_sha1",0xec9ac159,Crypt_hmac_sha1,56,2,{0x0,0xb8,}, + "ideacbc",0xac616ba,Crypt_ideacbc,48,2,{0x0,0xc0,}, + "ideaecb",0xac616ba,Crypt_ideaecb,48,2,{0x0,0xc0,}, + "ideasetup",0x44452583,Crypt_ideasetup,40,2,{0x0,0xc0,}, + "md4",0x7656377,Crypt_md4,48,2,{0x0,0xb0,}, + "md5",0x7656377,Crypt_md5,48,2,{0x0,0xb0,}, + "rc4",0xd051c505,Crypt_rc4,48,2,{0x0,0xc0,}, + "rc4back",0x3643caf7,Crypt_rc4back,40,2,{0x0,0x80,}, + "rc4setup",0x6fa90725,Crypt_rc4setup,40,2,{0x0,0x80,}, + "rc4skip",0x3643caf7,Crypt_rc4skip,40,2,{0x0,0x80,}, + "rsadecrypt",0x91e80677,Crypt_rsadecrypt,40,2,{0x0,0xc0,}, + "rsaencrypt",0x3cddeb19,Crypt_rsaencrypt,40,2,{0x0,0xc0,}, + "rsafill",0x621f5851,Crypt_rsafill,56,2,{0x0,0xf8,}, + "rsagen",0xa59005ba,Crypt_rsagen,48,0,{0}, + "sha1",0x7656377,Crypt_sha1,48,2,{0x0,0xb0,}, + "sha224",0x7656377,Crypt_sha224,48,2,{0x0,0xb0,}, + "sha256",0x7656377,Crypt_sha256,48,2,{0x0,0xb0,}, + "sha384",0x7656377,Crypt_sha384,48,2,{0x0,0xb0,}, + "sha512",0x7656377,Crypt_sha512,48,2,{0x0,0xb0,}, + "sign",0xe955b4f2,Crypt_sign,40,2,{0x0,0xc0,}, + "sktopk",0x132f856e,Crypt_sktopk,40,2,{0x0,0x80,}, + "verify",0xff419b7b,Crypt_verify,48,2,{0x0,0xe0,}, + 0 +}; +#define Cryptmodlen 36 diff --git a/libinterp/das-386.c b/libinterp/das-386.c new file mode 100644 index 0000000..bc34c1a --- /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-arm.c b/libinterp/das-arm.c new file mode 100644 index 0000000..9ba9011 --- /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 0000000..4237320 --- /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 0000000..90d7813 --- /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 +idiv(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", idiv, ir3}, + {31, 459, OEM, "DIVWU%V%C", idiv, 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", idiv, "%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-sparc.c b/libinterp/das-sparc.c new file mode 100644 index 0000000..fb5280a --- /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 0000000..459a3a7 --- /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 0000000..115e0b4 --- /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/dec.c b/libinterp/dec.c new file mode 100644 index 0000000..d816994 --- /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 0000000..f81749c --- /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 0000000..7b82502 --- /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 0000000..e885edc --- /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 0000000..7b82502 --- /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 0000000..e885edc --- /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 0000000..dc285a7 --- /dev/null +++ b/libinterp/draw.c @@ -0,0 +1,2622 @@ +#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" + +#include "tk.h" + +#include <stdio.h> +#include <string.h> +#include <float.h> +#include <math.h> + +#define NANOSVG_IMPLEMENTATION +#define NANOSVG_ALL_COLOR_KEYWORDS // Include full list of color keywords. +#include "svg/nanosvg.h" +#define NANOSVGRAST_IMPLEMENTATION +#include "svg/nanosvgrast.h" + + +#include "png/lodepng.h" + + +#ifdef ANDROID +#include <android/log.h> + +#define LOG_TAG "Inferno DRAW" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#else +#define LOGI(...) print(__VA_ARGS__) +#define LOGW(...) print(__VA_ARGS__) +#define LOGE(...) print(__VA_ARGS__) +#endif + + + +/* + * 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*); + +extern char rootdir[]; + +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; + + TkTop *t; + + f = fp; + destroy(*f->ret); + *f->ret = H; + + t = (currun())->tktop; + if(t && t->dd){ + *f->ret = t->dd; + return; + } + + 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; + int len = strlen(name); + char c1, c2, c3, c4; + + c4 = name[len-1]; + c3 = name[len-2]; + c2 = name[len-3]; + c1 = name[len-4]; + + if( + c1 == '.' && + (c2 == 'p' || c2 == 'P') && + (c3 == 'n' || c3 == 'N') && + (c4 == 'g' || c4 == 'G') + ){ + unsigned error; + unsigned char* image; + unsigned w, h, x, y; + + char filename[128]; + + Rectangle r; + + int locked; + int nbytes = 0; + + float scale = 1.0; + + int dst_size = -1; + +//LOGI("rd png 1 %s ", name); + if(name[0] == ':'){ + name++; + dst_size = atoi(name); +//LOGI("rd png 2 %d ", dst_size); + for( ; *name != ':' && *name != '\0'; name++) + ; + if(*name == ':') + name++; + } +//LOGI("rd png 3 %s ", name); + if(name == nil || name[0] == '\0') + return nil; + + locked = 1; + + snprint(filename, 127, "%s/%s", rootdir, name); +//LOGI("PNG 0: showing %s\n", filename); + /*load the PNG in one function call*/ + error = lodepng_decode32_file(&image, &w, &h, filename); + +//LOGI("PNG %d: image=%x, w=%d, h=%d\n", 1, image, w, h); + /*stop if there is an error*/ + if(error || image == nil){ + LOGE("PNG decoder error %u: %s\n", error, lodepng_error_text(error)); + return nil; + } + + if(dst_size > 0 && w != 0 && h != 0){ + char *ti = NULL; + int nw, nh, z, q; + + if(w > h) + scale = (float)dst_size/(float)w; + else + scale = (float)dst_size/(float)h; + + nw = (int)(scale * (float)w); + nh = (int)(scale * (float)h); + + ti = malloc(nw * nh * 4); + + for(z = 0; z < nh; z++){ + for(q = 0; q < nw; q++){ + float xpos = (float)q / scale; + float ypos = (float)z / scale; + + int x = (int)xpos; + int y = (int)ypos; + + //if(x >= w) x = w-1; + //if(y >= h) y = h-1; + + ti[z*nw*4 + 4*q] = image[y*w*4 + 4*x]; + ti[z*nw*4 + 4*q+1] = image[y*w*4 + 4*x+1]; + ti[z*nw*4 + 4*q+2] = image[y*w*4 + 4*x+2]; + ti[z*nw*4 + 4*q+3] = image[y*w*4 + 4*x+3]; + } + } + free(image); + image = ti; + + w = nw; + h = nh; + } + + r.min.x = 0; + r.min.y = 0; + r.max = r.min; + r.max.x += w; + r.max.y += h; + + nbytes = w*h*4; + + { + int j; + for(j=0; j<nbytes; j+=4){ + char tmp = image[j]; + image[j] = image[j+2]; + image[j+2] = tmp; + } + } + +//LOGI("PNG %d:\n", 2); + locked = lockdisplay(disp); + i = allocimage(disp, r, ARGB32, 0, DTransparent); +//LOGI("PNG %d: i=%x\n", 3, i); + if(i != nil){ +//LOGI("PNG 3.5: nb=%d\n", loadimage(i, r, image, nbytes) ); + if (loadimage(i, r, image, nbytes) != nbytes) { + freeimage(i); + i = nil; + } + } +//LOGI("PNG 3.7:\n"); + free(image); +//LOGI("PNG %d:\n", 4); + if(locked) + unlockdisplay(disp); +//LOGI("PNG %d:\n", 5); + + }else if( + c1 == '.' && + (c2 == 's' || c2 == 'S') && + (c3 == 'v' || c3 == 'V') && + (c4 == 'g' || c4 == 'G') + ){ + unsigned char* image = nil; + unsigned w, h, x, y; + char filename[128]; + + Rectangle r; + + int locked; + int nbytes = 0; + + NSVGimage *svg = nil; + + NSVGrasterizer *rast = nil; + + float scale = 1.0; + + int dst_size = -1; + +LOGI("rd img 1 %s ", name); + if(name[0] == ':'){ + name++; + dst_size = atoi(name); +LOGI("rd img 2 %d ", dst_size); + for( ; *name != ':' && *name != '\0'; name++) + ; + if(*name == ':') + name++; + } +LOGI("rd img 3 %s ", name); + if(name == nil || name[0] == '\0') + return nil; + + locked = 0; + + snprint(filename, 127, "%s/%s", rootdir, name); +//LOGI("SVG showing %s\n", filename); + svg = nsvgParseFromFile(filename, "px", 72.0f); + if(svg == nil){ + return nil; + } + + if(dst_size > 0){ + if(svg->width > svg->height) + scale = ((float)dst_size) / ((float)svg->width); + else + scale = ((float)dst_size) / ((float)svg->height); + } + + w = (int)(scale * (float)svg->width); + h = (int)(scale * (float)svg->height); +LOGI("rd img 4 %f, %dx%d ", scale, w, h); + + rast = nsvgCreateRasterizer(); + if (rast == nil) { + nsvgDelete(svg); + fprint(2, "Could not init rasterizer.\n"); + return nil; + } + + image = malloc(w*h*4); + if (image == NULL) { + fprint(2, "Could not alloc image buffer.\n"); + nsvgDeleteRasterizer(rast); + nsvgDelete(svg); + return nil; + } + + nsvgRasterize(rast, svg, 0,0, scale, image, w, h, w*4); + + nsvgDeleteRasterizer(rast); + nsvgDelete(svg); + + r.min.x = 0; + r.min.y = 0; + r.max = r.min; + r.max.x += w; + r.max.y += h; + + nbytes = w*h*4; + + locked = lockdisplay(disp); + i = allocimage(disp, r, ARGB32, 0, DTransparent); + if(i != nil){ + if (loadimage(i, r, image, nbytes) != nbytes) { + freeimage(i); + i = nil; + } + } + free(image); + if (locked) + unlockdisplay(disp); + + }else{ + 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){ + Cache *c = cacheinstall(fcache, disp, name, font, "font"); + if(c) + c->ref++; + }else + 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 0000000..f69eea9 --- /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 0000000..860b119 --- /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 0000000..eba89be --- /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 0000000..fd748af --- /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 0000000..55a2c4c --- /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 0000000..7da4b2d --- /dev/null +++ b/libinterp/heap.c @@ -0,0 +1,533 @@ +#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(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); +} + +Type* +dtype(void (*destroy)(Heap*, int), int size, uchar *map, int mapsize) +{ + Type *t; + + t = malloc(sizeof(Type)-sizeof(t->map)+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; +} + +void* +checktype(void *v, Type *t, char *name, int newref) +{ + Heap *h; + + if(v == H || v == nil) + error(exNilref); + h = D2H(v); + if(t == nil || h->t != t) + errorf("%s: %s", exType, name); + if(newref){ + h->ref++; + Setmark(h); + } + return v; +} + +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 0000000..80fffa3 --- /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 0000000..5728420 --- /dev/null +++ b/libinterp/ipint.c @@ -0,0 +1,848 @@ +#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 "ipint.h" +#include "raise.h" + +#include "ipintsmod.h" + +enum +{ + MaxBigBytes = 1024 +}; + +/* infinite precision integer */ +struct IPint +{ + IPints_IPint x; + mpint* b; +}; + +Type *TIPint; +static uchar IPintmap[] = IPints_IPint_map; + +#define MP(x) checkIPint((x)) + +void +ipintsmodinit(void) +{ + /* can be called from modinit, Keyring or Crypt */ + if(TIPint == nil) + TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap)); + builtinmod("$IPints", IPintsmodtab, IPintsmodlen); +} + +//IPints_IPint* +void* +newIPint(mpint* b) +{ + Heap *h; + IPint *ip; + + if(b == nil) + error(exHeap); + h = heap(TIPint); /* TO DO: caller might lose other values if heap raises error here */ + ip = H2D(IPint*, h); + ip->b = b; + return (IPints_IPint*)ip; +} + +mpint* +checkIPint(void *a) +{ + IPints_IPint *v; + IPint *ip; + + v = a; + ip = (IPint*)v; + if(ip == H || ip == nil) + error(exNilref); + if(D2H(ip)->t != TIPint) + error(exType); + return ip->b; /* non-nil by construction */ +} + +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_iptob64z(void *fp) +{ + F_IPint_iptob64 *f; + mpint *b; + char buf[MaxBigBytes]; /* TO DO: should allocate these */ + uchar *p; + int n, o; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + b = MP(f->i); + n = (b->top+1)*Dbytes; + p = malloc(n+1); + if(p == nil) + error(exHeap); + n = mptobe(b, p+1, n, nil); + if(n < 0){ + free(p); + return; + } + p[0] = 0; + if(n != 0 && (p[1]&0x80)){ + /* force leading 0 byte for compatibility with older representation */ + o = 0; + n++; + }else + o = 1; + enc64(buf, sizeof(buf), p+o, n); + retstr(buf, f->ret); + free(p); +} + +void +IPint_iptob64(void *fp) +{ + F_IPint_iptob64 *f; + char buf[MaxBigBytes]; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + mptoa(MP(f->i), 64, buf, sizeof(buf)); + retstr(buf, f->ret); +} + +void +IPint_iptobytes(void *fp) +{ + F_IPint_iptobytes *f; + uchar buf[MaxBigBytes]; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + /* 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]; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + *f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil)); +} + +void +IPint_iptostr(void *fp) +{ + F_IPint_iptostr *f; + char buf[MaxBigBytes]; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + mptoa(MP(f->i), f->base, buf, sizeof(buf)); + retstr(buf, f->ret); +} + +static IPints_IPint* +strtoipint(String *s, int base) +{ + char *p, *q; + mpint *b; + + p = string2c(s); + b = strtomp(p, &q, base, nil); + if(b == nil) + return H; + while(*q == '=') + q++; + if(q == p || *q != 0){ + mpfree(b); + return H; + } + return newIPint(b); +} + +void +IPint_b64toip(void *fp) +{ + F_IPint_b64toip *f; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + *f->ret = strtoipint(f->str, 64); +} + +void +IPint_bytestoip(void *fp) +{ + F_IPint_bytestoip *f; + mpint *b; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + 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; + mpint *b; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + 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; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + *f->ret = strtoipint(f->str, f->base); +} + +/* create a random integer */ +void +IPint_random(void *fp) +{ + F_IPint_random *f; + mpint *b; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + release(); + b = mprand(f->nbits, genrandom, nil); + acquire(); + *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; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + *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; + mpint *ret, *mod, *base, *exp; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + base = MP(f->base); + exp = MP(f->exp); + if(f->mod != H) + mod = MP(f->mod); + else + mod = nil; + ret = mpnew(0); + if(ret != nil) + mpexp(base, exp, mod, ret); + *f->ret = newIPint(ret); +} + +/* multiplicative inverse */ +void +IPint_invert(void *fp) +{ + F_IPint_invert *f; + mpint *ret; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + 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; + mpint *i1, *i2, *ret; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpadd(i1, i2, ret); + + *f->ret = newIPint(ret); +} +void +IPint_sub(void *fp) +{ + F_IPint_sub *f; + mpint *i1, *i2, *ret; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpsub(i1, i2, ret); + + *f->ret = newIPint(ret); +} +void +IPint_mul(void *fp) +{ + F_IPint_mul *f; + mpint *i1, *i2, *ret; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpmul(i1, i2, ret); + + *f->ret = newIPint(ret); +} +void +IPint_div(void *fp) +{ + F_IPint_div *f; + mpint *i1, *i2, *quo, *rem; + void *v; + + f = fp; + v = f->ret->t0; + f->ret->t0 = H; + destroy(v); + v = f->ret->t1; + f->ret->t1 = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + 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_mod(void *fp) +{ + F_IPint_mod *f; + mpint *i1, *i2, *ret; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpmod(i1, i2, ret); + + *f->ret = newIPint(ret); +} +void +IPint_neg(void *fp) +{ + F_IPint_neg *f; + mpint *ret; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + ret = mpcopy(MP(f->i)); + if(ret == nil) + error(exHeap); + ret->sign = -ret->sign; + + *f->ret = newIPint(ret); +} + +/* copy */ +void +IPint_copy(void *fp) +{ + F_IPint_copy *f; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + *f->ret = newIPint(mpcopy(MP(f->i))); +} + + +/* equality */ +void +IPint_eq(void *fp) +{ + F_IPint_eq *f; + + f = fp; + *f->ret = mpcmp(MP(f->i1), MP(f->i2)) == 0; +} + +/* compare */ +void +IPint_cmp(void *fp) +{ + F_IPint_eq *f; + + f = fp; + *f->ret = mpcmp(MP(f->i1), MP(f->i2)); +} + +/* shifts */ +void +IPint_shl(void *fp) +{ + F_IPint_shl *f; + mpint *ret, *i; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i = MP(f->i); + ret = mpnew(0); + if(ret != nil) + mpleft(i, f->n, ret); + *f->ret = newIPint(ret); +} +void +IPint_shr(void *fp) +{ + F_IPint_shr *f; + mpint *ret, *i; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i = MP(f->i); + ret = mpnew(0); + if(ret != nil) + mpright(i, f->n, ret); + *f->ret = newIPint(ret); +} + +static void +mpand(mpint *b, mpint *m, mpint *res) +{ + int i; + + res->sign = b->sign; + if(b->top == 0 || m->top == 0){ + res->top = 0; + return; + } + mpbits(res, b->top*Dbits); + res->top = b->top; + for(i = b->top; --i >= 0;){ + if(i < m->top) + res->p[i] = b->p[i] & m->p[i]; + else + res->p[i] = 0; + } + mpnorm(res); +} + +static void +mpor(mpint *b1, mpint *b2, mpint *res) +{ + mpint *t; + int i; + + if(b2->top > b1->top){ + t = b1; + b1 = b2; + b2 = t; + } + if(b1->top == 0){ + mpassign(b2, res); + return; + } + if(b2->top == 0){ + mpassign(b1, res); + return; + } + mpassign(b1, res); + for(i = b2->top; --i >= 0;) + res->p[i] |= b2->p[i]; + mpnorm(res); +} + +static void +mpxor(mpint *b1, mpint *b2, mpint *res) +{ + mpint *t; + int i; + + if(b2->top > b1->top){ + t = b1; + b1 = b2; + b2 = t; + } + if(b1->top == 0){ + mpassign(b2, res); + return; + } + if(b2->top == 0){ + mpassign(b1, res); + return; + } + mpassign(b1, res); + for(i = b2->top; --i >= 0;) + res->p[i] ^= b2->p[i]; + mpnorm(res); +} + +static void +mpnot(mpint *b1, mpint *res) +{ + int i; + + mpbits(res, Dbits*b1->top); + res->sign = 1; + res->top = b1->top; + for(i = res->top; --i >= 0;) + res->p[i] = ~b1->p[i]; + mpnorm(res); +} + +/* bits */ +void +IPint_and(void *fp) +{ + F_IPint_and *f; + mpint *ret, *i1, *i2; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpand(i1, i2, ret); + *f->ret = newIPint(ret); +} + +void +IPint_ori(void *fp) +{ + F_IPint_ori *f; + mpint *ret, *i1, *i2; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpor(i1, i2, ret); + *f->ret = newIPint(ret); +} + +void +IPint_xor(void *fp) +{ + F_IPint_xor *f; + mpint *ret, *i1, *i2; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + i2 = MP(f->i2); + ret = mpnew(0); + if(ret != nil) + mpxor(i1, i2, ret); + *f->ret = newIPint(ret); +} + +void +IPint_not(void *fp) +{ + F_IPint_not *f; + mpint *ret, *i1; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + i1 = MP(f->i1); + ret = mpnew(0); + if(ret != nil) + mpnot(i1, ret); + *f->ret = newIPint(ret); +} + +/* + * primes + */ + +void +IPints_probably_prime(void *fp) +{ + F_IPints_probably_prime *f; + + f = fp; + release(); + *f->ret = probably_prime(checkIPint(f->n), f->nrep); + acquire(); +} + +void +IPints_genprime(void *fp) +{ + F_IPints_genprime *f; + mpint *p; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + p = mpnew(0); + release(); + genprime(p, f->nbits, f->nrep); + acquire(); + *f->ret = newIPint(p); +} + +void +IPints_genstrongprime(void *fp) +{ + F_IPints_genstrongprime *f; + mpint *p; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + p = mpnew(0); + release(); + genstrongprime(p, f->nbits, f->nrep); + acquire(); + *f->ret = newIPint(p); +} + +void +IPints_gensafeprime(void *fp) +{ + F_IPints_gensafeprime *f; + mpint *p, *alpha; + void *v; + + f = fp; + v = f->ret->t0; + f->ret->t0 = H; + destroy(v); + v = f->ret->t1; + f->ret->t1 = H; + destroy(v); + + p = mpnew(0); + alpha = mpnew(0); + release(); + gensafeprime(p, alpha, f->nbits, f->nrep); + acquire(); + f->ret->t0 = newIPint(p); + f->ret->t1 = newIPint(alpha); +} + +void +IPints_DSAprimes(void *fp) +{ + F_IPints_DSAprimes *f; + mpint *p, *q; + Heap *h; + void *v; + + f = fp; + v = f->ret->t0; + f->ret->t0 = H; + destroy(v); + v = f->ret->t1; + f->ret->t1 = H; + destroy(v); + v = f->ret->t2; + f->ret->t2 = H; + destroy(v); + + h = heaparray(&Tbyte, SHA1dlen); + f->ret->t2 = H2D(Array*, h); + + p = mpnew(0); + q = mpnew(0); + release(); + DSAprimes(q, p, f->ret->t2->data); + acquire(); + f->ret->t0 = newIPint(q); + f->ret->t1 = newIPint(p); +} diff --git a/libinterp/ipint.h b/libinterp/ipint.h new file mode 100644 index 0000000..a730f4f --- /dev/null +++ b/libinterp/ipint.h @@ -0,0 +1,12 @@ +typedef struct IPint IPint; + +#pragma incomplete IPint + +//Keyring_IPint* newIPint(mpint*); +void* newIPint(mpint*); +//mpint* checkIPint(Keyring_IPint*); +mpint* checkIPint(void*); +void freeIPint(Heap*, int); +void ipintsmodinit(void); + +extern Type* TIPint; diff --git a/libinterp/ipintsmod.h b/libinterp/ipintsmod.h new file mode 100644 index 0000000..6b96d75 --- /dev/null +++ b/libinterp/ipintsmod.h @@ -0,0 +1,40 @@ +typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab; +Runtab IPintsmodtab[]={ + "DSAprimes",0x40d03bb6,IPints_DSAprimes,32,0,{0}, + "IPint.add",0xa47c1b24,IPint_add,40,2,{0x0,0xc0,}, + "IPint.and",0xa47c1b24,IPint_and,40,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,}, + "IPint.cmp",0x79774f9e,IPint_cmp,40,2,{0x0,0xc0,}, + "IPint.copy",0x491fbd11,IPint_copy,40,2,{0x0,0x80,}, + "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,}, + "genprime",0x70bcd6f1,IPints_genprime,40,0,{0}, + "gensafeprime",0x9a3f0392,IPints_gensafeprime,40,0,{0}, + "genstrongprime",0x70bcd6f1,IPints_genstrongprime,40,0,{0}, + "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.iptob64z",0xfab4eb8a,IPint_iptob64z,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,}, + "IPint.mod",0xa47c1b24,IPint_mod,40,2,{0x0,0xc0,}, + "IPint.mul",0xa47c1b24,IPint_mul,40,2,{0x0,0xc0,}, + "IPint.neg",0x491fbd11,IPint_neg,40,2,{0x0,0x80,}, + "IPint.not",0x491fbd11,IPint_not,40,2,{0x0,0x80,}, + "IPint.ori",0xa47c1b24,IPint_ori,40,2,{0x0,0xc0,}, + "probably_prime",0xd67dfdfa,IPints_probably_prime,40,2,{0x0,0x80,}, + "IPint.random",0x95dc8b6d,IPint_random,40,0,{0}, + "IPint.shl",0xc7b0bc01,IPint_shl,40,2,{0x0,0x80,}, + "IPint.shr",0xc7b0bc01,IPint_shr,40,2,{0x0,0x80,}, + "IPint.strtoip",0x12d7a943,IPint_strtoip,40,2,{0x0,0x80,}, + "IPint.sub",0xa47c1b24,IPint_sub,40,2,{0x0,0xc0,}, + "IPint.xor",0xa47c1b24,IPint_xor,40,2,{0x0,0xc0,}, + 0 +}; +#define IPintsmodlen 35 diff --git a/libinterp/keyring.c b/libinterp/keyring.c new file mode 100644 index 0000000..8b7fd40 --- /dev/null +++ b/libinterp/keyring.c @@ -0,0 +1,3083 @@ +#include "lib9.h" +#include "kernel.h" +#include <isa.h> +#include "interp.h" +#include <mp.h> +#include <libsec.h> +#include "pool.h" +#include "raise.h" + +/* arguably limbo -t should qualify type name */ +#define DigestState_copy Keyring_DigestState_copy +#define IPint_random Keyring_IPint_random +#include "keyringif.h" +#include "keyring.h" + +#include "ipint.h" +#include "../libkeyring/keys.h" + +static Type* TDigestState; +static Type* TAESstate; +static Type* TDESstate; +static Type* TIDEAstate; +static Type* TBFstate; +static Type* TRC4state; + +static Type* TSigAlg; +static Type* TCertificate; +static Type* TSK; +static Type* TPK; +static Type* TAuthinfo; + +static Type* TDSAsk; +static Type* TDSApk; +static Type* TDSAsig; +static Type* TEGsk; +static Type* TEGpk; +static Type* TEGsig; +static Type* TRSAsk; +static Type* TRSApk; +static Type* TRSAsig; + +enum { + Maxmsg= 4096 +}; + +static uchar DigestStatemap[] = Keyring_DigestState_map; +static uchar AESstatemap[] = Keyring_AESstate_map; +static uchar DESstatemap[] = Keyring_DESstate_map; +static uchar IDEAstatemap[] = Keyring_IDEAstate_map; +static uchar BFstatemap[] = Keyring_BFstate_map; +static uchar RC4statemap[] = Keyring_RC4state_map; + +static uchar SigAlgmap[] = Keyring_SigAlg_map; +static uchar SKmap[] = Keyring_SK_map; +static uchar PKmap[] = Keyring_PK_map; +static uchar Certificatemap[] = Keyring_Certificate_map; +static uchar Authinfomap[] = Keyring_Authinfo_map; +static uchar DSAskmap[] = Keyring_DSAsk_map; +static uchar DSApkmap[] = Keyring_DSApk_map; +static uchar DSAsigmap[] = Keyring_DSAsig_map; +static uchar EGskmap[] = Keyring_EGsk_map; +static uchar EGpkmap[] = Keyring_EGpk_map; +static uchar EGsigmap[] = Keyring_EGsig_map; +static uchar RSAskmap[] = Keyring_RSAsk_map; +static uchar RSApkmap[] = Keyring_RSApk_map; +static uchar RSAsigmap[] = Keyring_RSAsig_map; + +static PK* checkPK(Keyring_PK *k); + +extern void setid(char*, int); +extern vlong osusectime(void); +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"; +static char exBadBsize[] = "data not multiple of block size"; +static char exBadKey[] = "bad encryption key"; +static char exBadDigest[] = "bad digest value"; +static char exBadIvec[] = "bad ivec"; +static char exBadState[] = "bad encryption state"; + +typedef struct XBFstate XBFstate; + +/* BF state */ +struct XBFstate +{ + Keyring_BFstate x; + BFstate state; +}; + +/* convert a Big to base64 ascii */ +int +bigtobase64(mpint* 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) +{ + mpint *b; + char *buf; + int n; + + b = va_arg(f->args, mpint*); + 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; +} + +static void* +newthing(Type *t, int add) +{ + Heap *h; + + h = heap(t); + if(add) + ptradd(h); + return H2D(void*, h); +} + +static Keyring_IPint* +ipcopymp(mpint* b) +{ + if(b == nil) + return H; + return newIPint(mpcopy(b)); +} + +/* convert a base64 string to a big */ +mpint* +base64tobig(char *str, char **strp) +{ + int n; + char *p; + mpint *b; + uchar hex[(MaxBigBytes*6 + 7)/8]; + + for(p = str; *p && *p != '\n'; p++) + ; + if(p == str) + return nil; + 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 mpints 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, *owner; + 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", string2c(sa->x.name)); + owner = string2c(sk->x.owner); + if(*owner) + fmtprint(&o, " owner=%q", 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); +} + +static 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; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + 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, *owner; + 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", string2c(sa->x.name)); + owner = string2c(pk->x.owner); + if(*owner) + fmtprint(&o, " owner=%q", 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; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + *f->ret = (Keyring_Certificate*)strtocert(string2c(f->s)); +} + +static Certificate* +sign(SK *sk, char *ha, ulong exp, uchar *a, int len) +{ + Certificate *c; + mpint *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; + mpint *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); +} + +void +Keyring_signm(void *fp) +{ + F_Keyring_signm *f; + Certificate *c; + mpint *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) +{ + mpint *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; + mpint *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 +Keyring_DigestState_copy(void *fp) +{ + F_DigestState_copy *f; + Heap *h; + XDigestState *ds, *ods; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->d != H){ + ods = checktype(f->d, TDigestState, "DigestState", 0); + h = heap(TDigestState); + ds = H2D(XDigestState*, h); + memmove(&ds->state, &ods->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) + error(exInval); + cbuf = nil; + } + + if(digest != H){ + if(digest->len < dlen) + error(exBadDigest); + cdigest = digest->data; + } else + cdigest = nil; + + if(state == H){ + h = heap(TDigestState); + ds = H2D(XDigestState*, h); + memset(&ds->state, 0, sizeof(ds->state)); + } else + ds = checktype(state, TDigestState, "DigestState", 1); + + (*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_sha224(void *fp) +{ + F_Keyring_sha224 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224); +} + +void +Keyring_sha256(void *fp) +{ + F_Keyring_sha256 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256); +} + +void +Keyring_sha384(void *fp) +{ + F_Keyring_sha384 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384); +} + +void +Keyring_sha512(void *fp) +{ + F_Keyring_sha512 *f; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512); +} + +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) + error(exInval); + cdata = nil; + } + + if(key == H || key->len > 64) + error(exBadKey); + + if(digest != H){ + if(digest->len < dlen) + error(exBadDigest); + cdigest = digest->data; + } else + cdigest = nil; + + if(state == H){ + h = heap(TDigestState); + ds = H2D(XDigestState*, h); + memset(&ds->state, 0, sizeof(ds->state)); + } else + ds = checktype(state, TDigestState, "DigestState", 1); + + (*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; + mpint *p, *alpha; + void *v; + + f = fp; + v = f->ret->t0; + f->ret->t0 = H; + destroy(v); + v = f->ret->t1; + f->ret->t1 = H; + destroy(v); + + p = mpnew(0); + alpha = mpnew(0); + release(); + if(f->nbits == 1024) + DSAprimes(alpha, p, nil); + else + gensafeprime(p, alpha, f->nbits, 0); + acquire(); + 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->n; + if(n < 0 || n > f->buf->len) + error(exBounds); + *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; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + 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; + mpint *r0, *r1, *p, *alpha, *alphar0, *alphar1, *alphar0r1; + 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; + 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 = checkIPint(f->info->p); + alpha = checkIPint(f->info->alpha); + + if(p->sign == -1) { + err = "-ve modulus"; + goto out; + } + + r0 = mpnew(0); + r1 = mpnew(0); + alphar0 = mpnew(0); + alphar0r1 = mpnew(0); + + /* generate alpha**r0 */ +if(0)print("X"); + release(); + mprand(mpsignif(p), genrandom, r0); + 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 syntax"; + 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(r0 != nil){ + 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; + mpint *p, *alpha; + + f = fp; + *f->ret = -1; + + if(f->filename == H) + error(exNilref); + if(f->info == H) + error(exNilref); + alpha = checkIPint(f->info->alpha); + p = checkIPint(f->info->p); + 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(alpha, buf, Maxbuf); + if(sendmsg(fd, buf, n) <= 0) + goto out; + + /* diffie hellman modulus */ + n = bigtobase64(p, 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; + mpint *b; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + 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){ + r = *f->ret; + *f->ret = H; + destroy(r); + } + 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); + + ipintsmodinit(); /* in case only Keyring is configured */ + 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)); + TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap, + sizeof(BFstatemap)); + TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap, + sizeof(RC4statemap)); + TAuthinfo = dtype(freeheap, sizeof(Keyring_Authinfo), Authinfomap, sizeof(Authinfomap)); + TDSAsk = dtype(freeheap, sizeof(Keyring_DSAsk), DSAskmap, sizeof(DSAskmap)); + TDSApk = dtype(freeheap, sizeof(Keyring_DSApk), DSApkmap, sizeof(DSApkmap)); + TDSAsig = dtype(freeheap, sizeof(Keyring_DSAsig), DSAsigmap, sizeof(DSAsigmap)); + TEGsk = dtype(freeheap, sizeof(Keyring_EGsk), EGskmap, sizeof(EGskmap)); + TEGpk = dtype(freeheap, sizeof(Keyring_EGpk), EGpkmap, sizeof(EGpkmap)); + TEGsig = dtype(freeheap, sizeof(Keyring_EGsig), EGsigmap, sizeof(EGsigmap)); + TRSAsk = dtype(freeheap, sizeof(Keyring_RSAsk), RSAskmap, sizeof(RSAskmap)); + TRSApk = dtype(freeheap, sizeof(Keyring_RSApk), RSApkmap, sizeof(RSApkmap)); + TRSAsig = dtype(freeheap, sizeof(Keyring_RSAsig), RSAsigmap, sizeof(RSAsigmap)); + + 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 < 0 || n > f->a->len) + error(exBounds); + *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; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->key == H || f->key->len < 8) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len < 8) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + 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; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + ds = checktype(f->state, TDESstate, exBadState, 0); + 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->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + ds = checktype(f->state, TDESstate, exBadState, 0); + 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; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->key == H || f->key->len < 16) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len < 8) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + 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; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + is = checktype(f->state, TIDEAstate, exBadState, 0); + 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->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + is = checktype(f->state, TIDEAstate, exBadState, 0); + 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; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->key == H || + f->key->len != 16 && f->key->len != 24 && f->key->len != 32) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len < AESbsize) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + 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->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + + is = checktype(f->state, TAESstate, exBadState, 0); + p = f->buf->data; + + if(f->direction == 0) + aesCBCencrypt(p, f->n, &is->state); + else + aesCBCdecrypt(p, f->n, &is->state); +} + +void +Keyring_blowfishsetup(void *fp) +{ + F_Keyring_blowfishsetup *f; + Heap *h; + XBFstate *is; + uchar *ivec; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->key == H || f->key->len <= 0) + error(exBadKey); + if(f->ivec != H){ + if(f->ivec->len != BFbsize) + error(exBadIvec); + ivec = f->ivec->data; + }else + ivec = nil; + + h = heap(TBFstate); + is = H2D(XBFstate*, h); + + setupBFstate(&is->state, f->key->data, f->key->len, ivec); + + *f->ret = (Keyring_BFstate*)is; +} + +void +Keyring_blowfishcbc(void *fp) +{ + F_Keyring_blowfishcbc *f; + XBFstate *is; + uchar *p; + + f = fp; + + if(f->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + if(f->n & 7) + error(exBadBsize); + + is = checktype(f->state, TBFstate, exBadState, 0); + p = f->buf->data; + + if(f->direction == 0) + bfCBCencrypt(p, f->n, &is->state); + else + bfCBCdecrypt(p, f->n, &is->state); +} + +void +Keyring_rc4setup(void *fp) +{ + F_Keyring_rc4setup *f; + Heap *h; + XRC4state *is; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + + if(f->seed == 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->buf == H) + return; + if(f->n < 0 || f->n > f->buf->len) + error(exBounds); + is = checktype(f->state, TRC4state, exBadState, 0); + p = f->buf->data; + rc4(&is->state, p, f->n); +} + +void +Keyring_rc4skip(void *fp) +{ + F_Keyring_rc4skip *f; + XRC4state *is; + + f = fp; + is = checktype(f->state, TRC4state, exBadState, 0); + rc4skip(&is->state, f->n); +} + +void +Keyring_rc4back(void *fp) +{ + F_Keyring_rc4back *f; + XRC4state *is; + + f = fp; + is = checktype(f->state, TRC4state, exBadState, 0); + rc4back(&is->state, f->n); +} + +/* + * public/secret keys, signing and verifying + */ + +static void +dsapk2pub(DSApub* p, Keyring_DSApk* pk) +{ + if(pk == H) + error(exNilref); + p->p = checkIPint(pk->p); + p->q = checkIPint(pk->q); + p->alpha = checkIPint(pk->alpha); + p->key = checkIPint(pk->key); +} + +static void +dsask2priv(DSApriv* p, Keyring_DSAsk* sk) +{ + if(sk == H || sk->pk == H) + error(exNilref); + dsapk2pub(&p->pub, sk->pk); + p->secret = checkIPint(sk->secret); +} + +static void +dsapriv2sk(Keyring_DSAsk* sk, DSApriv* p) +{ + Keyring_DSApk* pk; + + pk = sk->pk; + pk->p = ipcopymp(p->pub.p); + pk->q = ipcopymp(p->pub.q); + pk->alpha = ipcopymp(p->pub.alpha); + pk->key = ipcopymp(p->pub.key); + sk->secret = ipcopymp(p->secret); +} + +void +DSAsk_gen(void *fp) +{ + F_DSAsk_gen *f; + Keyring_DSAsk *sk; + DSApriv *p; + DSApub pub, *oldpk; + void *v; + + f = fp; + v = *f->ret; + sk = newthing(TDSAsk, 0); + sk->pk = newthing(TDSApk, 0); + *f->ret = sk; + destroy(v); + oldpk = nil; + if(f->oldpk != H){ + dsapk2pub(&pub, f->oldpk); + oldpk = &pub; + } + release(); + p = dsagen(oldpk); + acquire(); + dsapriv2sk(sk, p); + dsaprivfree(p); +} + +void +DSAsk_sign(void *fp) +{ + F_DSAsk_sign *f; + Keyring_DSAsig *sig; + DSApriv p; + mpint *m; + DSAsig *s; + void *v; + + f = fp; + v = *f->ret; + sig = newthing(TDSAsig, 0); + *f->ret = sig; + destroy(v); + + dsask2priv(&p, f->k); + m = checkIPint(f->m); + release(); + s = dsasign(&p, m); + acquire(); + sig->r = ipcopymp(s->r); + sig->s = ipcopymp(s->s); + dsasigfree(s); +} + +void +DSApk_verify(void *fp) +{ + F_DSApk_verify *f; + DSApub p; + DSAsig sig; + mpint *m; + + f = fp; + *f->ret = 0; + if(f->m == H || f->sig == H) + return; + dsapk2pub(&p, f->k); + sig.r = checkIPint(f->sig->r); + sig.s = checkIPint(f->sig->s); + m = checkIPint(f->m); + release(); + *f->ret = dsaverify(&p, &sig, m) == 0; + acquire(); +} + +static void +egpk2pub(EGpub* p, Keyring_EGpk* pk) +{ + if(pk == H) + error(exNilref); + p->p = checkIPint(pk->p); + p->alpha = checkIPint(pk->alpha); + p->key = checkIPint(pk->key); +} + +static void +egsk2priv(EGpriv* p, Keyring_EGsk* sk) +{ + if(sk == H || sk->pk == H) + error(exNilref); + egpk2pub(&p->pub, sk->pk); + p->secret = checkIPint(sk->secret); +} + +static void +egpriv2sk(Keyring_EGsk* sk, EGpriv* p) +{ + Keyring_EGpk* pk; + + pk = sk->pk; + pk->p = ipcopymp(p->pub.p); + pk->alpha = ipcopymp(p->pub.alpha); + pk->key = ipcopymp(p->pub.key); + sk->secret = ipcopymp(p->secret); +} + +void +EGsk_gen(void *fp) +{ + F_EGsk_gen *f; + Keyring_EGsk *sk; + EGpriv *p; + void *v; + + f = fp; + v = *f->ret; + sk = newthing(TEGsk, 0); + sk->pk = newthing(TEGpk, 0); + *f->ret = sk; + destroy(v); + release(); + for(;;){ + p = eggen(f->nlen, f->nrep); + if(mpsignif(p->pub.p) == f->nlen) + break; + egprivfree(p); + } + acquire(); + egpriv2sk(sk, p); + egprivfree(p); +} + +void +EGsk_sign(void *fp) +{ + F_EGsk_sign *f; + Keyring_EGsig *sig; + EGpriv p; + mpint *m; + EGsig *s; + void *v; + + f = fp; + v = *f->ret; + sig = newthing(TEGsig, 0); + *f->ret = sig; + destroy(v); + + egsk2priv(&p, f->k); + m = checkIPint(f->m); + release(); + s = egsign(&p, m); + acquire(); + sig->r = ipcopymp(s->r); + sig->s = ipcopymp(s->s); + egsigfree(s); +} + +void +EGpk_verify(void *fp) +{ + F_EGpk_verify *f; + EGpub p; + EGsig sig; + mpint *m; + + f = fp; + *f->ret = 0; + if(f->m == H || f->sig == H) + return; + egpk2pub(&p, f->k); + sig.r = checkIPint(f->sig->r); + sig.s = checkIPint(f->sig->s); + m = checkIPint(f->m); + release(); + *f->ret = egverify(&p, &sig, m) == 0; + acquire(); +} + +static void +rsapk2pub(RSApub* p, Keyring_RSApk* pk) +{ + if(pk == H) + error(exNilref); + memset(p, 0, sizeof(*p)); + p->n = checkIPint(pk->n); + p->ek = checkIPint(pk->ek); +} + +static void +rsask2priv(RSApriv* p, Keyring_RSAsk* sk) +{ + if(sk == H || sk->pk == H) + error(exNilref); + rsapk2pub(&p->pub, sk->pk); + p->dk = checkIPint(sk->dk); + p->p = checkIPint(sk->p); + p->q = checkIPint(sk->q); + p->kp = checkIPint(sk->kp); + p->kq = checkIPint(sk->kq); + p->c2 = checkIPint(sk->c2); +} + +static void +rsapriv2sk(Keyring_RSAsk* sk, RSApriv* p) +{ + Keyring_RSApk* pk; + + pk = sk->pk; + pk->n = ipcopymp(p->pub.n); + pk->ek = ipcopymp(p->pub.ek); + sk->dk = ipcopymp(p->dk); + sk->p = ipcopymp(p->p); + sk->q = ipcopymp(p->q); + sk->kp = ipcopymp(p->kp); + sk->kq = ipcopymp(p->kq); + sk->c2 = ipcopymp(p->c2); +} + +void +RSApk_encrypt(void *fp) +{ + F_RSApk_encrypt *f; + RSApub p; + mpint *m, *o; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + rsapk2pub(&p, f->k); + m = checkIPint(f->m); + release(); + o = rsaencrypt(&p, m, nil); + acquire(); + *f->ret = newIPint(o); +} + +void +RSAsk_gen(void *fp) +{ + F_RSAsk_gen *f; + Keyring_RSAsk *sk; + RSApriv *p; + void *v; + + f = fp; + v = *f->ret; + sk = newthing(TRSAsk, 0); + sk->pk = newthing(TRSApk, 0); + *f->ret = sk; + destroy(v); + release(); + for(;;){ + p = rsagen(f->nlen, f->elen, f->nrep); + if(mpsignif(p->pub.n) == f->nlen) + break; + rsaprivfree(p); + } + acquire(); + rsapriv2sk(sk, p); + rsaprivfree(p); +} + +void +RSAsk_fill(void *fp) +{ + F_RSAsk_fill *f; + Keyring_RSAsk *sk; + RSApriv *p; + void *v; + + f = fp; + v = *f->ret; + sk = newthing(TRSAsk, 0); + sk->pk = newthing(TRSApk, 0); + *f->ret = sk; + destroy(v); + release(); + p = rsafill(checkIPint(f->n), checkIPint(f->e), checkIPint(f->d), + checkIPint(f->p), checkIPint(f->q)); + acquire(); + if(p == nil) { + *f->ret = H; + destroy(sk); + }else{ + rsapriv2sk(sk, p); + rsaprivfree(p); + } +} + +void +RSAsk_decrypt(void *fp) +{ + F_RSAsk_decrypt *f; + RSApriv p; + mpint *m, *o; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + rsask2priv(&p, f->k); + m = checkIPint(f->m); + release(); + o = rsadecrypt(&p, m, nil); + acquire(); + *f->ret = newIPint(o); +} + +void +RSAsk_sign(void *fp) +{ + F_RSAsk_sign *f; + Keyring_RSAsig *sig; + RSApriv p; + mpint *m, *s; + void *v; + + f = fp; + v = *f->ret; + sig = newthing(TRSAsig, 0); + *f->ret = sig; + destroy(v); + + rsask2priv(&p, f->k); + m = checkIPint(f->m); + release(); + s = rsadecrypt(&p, m, nil); + acquire(); + sig->n = newIPint(s); +} + +void +RSApk_verify(void *fp) +{ + F_RSApk_verify *f; + RSApub p; + mpint *sig, *m, *t; + + f = fp; + *f->ret = 0; + if(f->m == H || f->sig == H) + return; + rsapk2pub(&p, f->k); + sig = checkIPint(f->sig->n); + m = checkIPint(f->m); + release(); + t = rsaencrypt(&p, sig, nil); + *f->ret = mpcmp(t, m) == 0; + mpfree(t); + acquire(); +} + +void +Keyring_IPint_random(void *fp) +{ + F_IPint_random *f; + mpint *b; + void *v; + + f = fp; + v = *f->ret; + *f->ret = H; + destroy(v); + + release(); + b = mprand(f->maxbits, genrandom, nil); + acquire(); + *f->ret = newIPint(b); +} diff --git a/libinterp/keyring.h b/libinterp/keyring.h new file mode 100644 index 0000000..f5ea7a1 --- /dev/null +++ b/libinterp/keyring.h @@ -0,0 +1,99 @@ +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,}, + "IPint.and",0xa47c1b24,IPint_and,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,}, + "blowfishcbc",0xac616ba,Keyring_blowfishcbc,48,2,{0x0,0xc0,}, + "blowfishsetup",0x44452583,Keyring_blowfishsetup,40,2,{0x0,0xc0,}, + "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,}, + "RSAsk.decrypt",0xf3b51b95,RSAsk_decrypt,40,2,{0x0,0xc0,}, + "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,}, + "RSApk.encrypt",0xdc0ec366,RSApk_encrypt,40,2,{0x0,0xc0,}, + "IPint.eq",0x79774f9e,IPint_eq,40,2,{0x0,0xc0,}, + "IPint.expmod",0xe6105024,IPint_expmod,48,2,{0x0,0xe0,}, + "RSAsk.fill",0x2ab0d50a,RSAsk_fill,56,2,{0x0,0xf8,}, + "RSAsk.gen",0xc197fd0,RSAsk_gen,48,0,{0}, + "DSAsk.gen",0x46f0eb94,DSAsk_gen,40,2,{0x0,0x80,}, + "EGsk.gen",0x4a59c528,EGsk_gen,40,0,{0}, + "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.iptob64z",0xfab4eb8a,IPint_iptob64z,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.mod",0xa47c1b24,IPint_mod,40,2,{0x0,0xc0,}, + "IPint.mul",0xa47c1b24,IPint_mul,40,2,{0x0,0xc0,}, + "IPint.neg",0x491fbd11,IPint_neg,40,2,{0x0,0x80,}, + "IPint.not",0x491fbd11,IPint_not,40,2,{0x0,0x80,}, + "IPint.ori",0xa47c1b24,IPint_ori,40,2,{0x0,0xc0,}, + "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,}, + "sha224",0x7656377,Keyring_sha224,48,2,{0x0,0xb0,}, + "sha256",0x7656377,Keyring_sha256,48,2,{0x0,0xb0,}, + "sha384",0x7656377,Keyring_sha384,48,2,{0x0,0xb0,}, + "sha512",0x7656377,Keyring_sha512,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,}, + "RSAsk.sign",0x5dbdc2fe,RSAsk_sign,40,2,{0x0,0xc0,}, + "DSAsk.sign",0x6e51e1b3,DSAsk_sign,40,2,{0x0,0xc0,}, + "EGsk.sign",0xca053e70,EGsk_sign,40,2,{0x0,0xc0,}, + "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,}, + "RSApk.verify",0x1857beff,RSApk_verify,48,2,{0x0,0xe0,}, + "DSApk.verify",0xeca448ff,DSApk_verify,48,2,{0x0,0xe0,}, + "EGpk.verify",0xfb1e256c,EGpk_verify,48,2,{0x0,0xe0,}, + "verifym",0x8b5b9f76,Keyring_verifym,48,2,{0x0,0xe0,}, + "writeauthinfo",0x5ba03002,Keyring_writeauthinfo,40,2,{0x0,0xc0,}, + "IPint.xor",0xa47c1b24,IPint_xor,40,2,{0x0,0xc0,}, + 0 +}; +#define Keyringmodlen 94 diff --git a/libinterp/keyringif.h b/libinterp/keyringif.h new file mode 100644 index 0000000..c3fd2c5 --- /dev/null +++ b/libinterp/keyringif.h @@ -0,0 +1,1692 @@ +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 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_BFstate Keyring_BFstate; +typedef struct Keyring_Authinfo Keyring_Authinfo; +typedef struct Keyring_RSApk Keyring_RSApk; +typedef struct Keyring_RSAsk Keyring_RSAsk; +typedef struct Keyring_RSAsig Keyring_RSAsig; +typedef struct Keyring_DSApk Keyring_DSApk; +typedef struct Keyring_DSAsk Keyring_DSAsk; +typedef struct Keyring_DSAsig Keyring_DSAsig; +typedef struct Keyring_EGpk Keyring_EGpk; +typedef struct Keyring_EGsk Keyring_EGsk; +typedef struct Keyring_EGsig Keyring_EGsig; +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 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_BFstate +{ + WORD x; +}; +#define Keyring_BFstate_size 4 +#define Keyring_BFstate_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 Keyring_RSApk +{ + Keyring_IPint* n; + Keyring_IPint* ek; +}; +#define Keyring_RSApk_size 8 +#define Keyring_RSApk_map {0xc0,} +struct Keyring_RSAsk +{ + Keyring_RSApk* pk; + Keyring_IPint* dk; + Keyring_IPint* p; + Keyring_IPint* q; + Keyring_IPint* kp; + Keyring_IPint* kq; + Keyring_IPint* c2; +}; +#define Keyring_RSAsk_size 28 +#define Keyring_RSAsk_map {0xfe,} +struct Keyring_RSAsig +{ + Keyring_IPint* n; +}; +#define Keyring_RSAsig_size 4 +#define Keyring_RSAsig_map {0x80,} +struct Keyring_DSApk +{ + Keyring_IPint* p; + Keyring_IPint* q; + Keyring_IPint* alpha; + Keyring_IPint* key; +}; +#define Keyring_DSApk_size 16 +#define Keyring_DSApk_map {0xf0,} +struct Keyring_DSAsk +{ + Keyring_DSApk* pk; + Keyring_IPint* secret; +}; +#define Keyring_DSAsk_size 8 +#define Keyring_DSAsk_map {0xc0,} +struct Keyring_DSAsig +{ + Keyring_IPint* r; + Keyring_IPint* s; +}; +#define Keyring_DSAsig_size 8 +#define Keyring_DSAsig_map {0xc0,} +struct Keyring_EGpk +{ + Keyring_IPint* p; + Keyring_IPint* alpha; + Keyring_IPint* key; +}; +#define Keyring_EGpk_size 12 +#define Keyring_EGpk_map {0xe0,} +struct Keyring_EGsk +{ + Keyring_EGpk* pk; + Keyring_IPint* secret; +}; +#define Keyring_EGsk_size 8 +#define Keyring_EGsk_map {0xc0,} +struct Keyring_EGsig +{ + Keyring_IPint* r; + Keyring_IPint* s; +}; +#define Keyring_EGsig_size 8 +#define Keyring_EGsig_map {0xc0,} +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_readn(void*); +typedef struct F_Sys_readn F_Sys_readn; +struct F_Sys_readn +{ + 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 4 +#define Sys_UTFerror 65533 +#define Sys_Runemax 1114111 +#define Sys_Runemask 2097151 +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 IPint_and(void*); +typedef struct F_IPint_and F_IPint_and; +struct F_IPint_and +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_IPint* i1; + Keyring_IPint* i2; +}; +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 Keyring_blowfishcbc(void*); +typedef struct F_Keyring_blowfishcbc F_Keyring_blowfishcbc; +struct F_Keyring_blowfishcbc +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Keyring_BFstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Keyring_blowfishsetup(void*); +typedef struct F_Keyring_blowfishsetup F_Keyring_blowfishsetup; +struct F_Keyring_blowfishsetup +{ + WORD regs[NREG-1]; + Keyring_BFstate** ret; + uchar temps[12]; + Array* key; + Array* ivec; +}; +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 RSAsk_decrypt(void*); +typedef struct F_RSAsk_decrypt F_RSAsk_decrypt; +struct F_RSAsk_decrypt +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_RSAsk* k; + Keyring_IPint* m; +}; +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 RSApk_encrypt(void*); +typedef struct F_RSApk_encrypt F_RSApk_encrypt; +struct F_RSApk_encrypt +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_RSApk* k; + Keyring_IPint* m; +}; +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 RSAsk_fill(void*); +typedef struct F_RSAsk_fill F_RSAsk_fill; +struct F_RSAsk_fill +{ + WORD regs[NREG-1]; + Keyring_RSAsk** ret; + uchar temps[12]; + Keyring_IPint* n; + Keyring_IPint* e; + Keyring_IPint* d; + Keyring_IPint* p; + Keyring_IPint* q; +}; +void RSAsk_gen(void*); +typedef struct F_RSAsk_gen F_RSAsk_gen; +struct F_RSAsk_gen +{ + WORD regs[NREG-1]; + Keyring_RSAsk** ret; + uchar temps[12]; + WORD nlen; + WORD elen; + WORD nrep; +}; +void DSAsk_gen(void*); +typedef struct F_DSAsk_gen F_DSAsk_gen; +struct F_DSAsk_gen +{ + WORD regs[NREG-1]; + Keyring_DSAsk** ret; + uchar temps[12]; + Keyring_DSApk* oldpk; +}; +void EGsk_gen(void*); +typedef struct F_EGsk_gen F_EGsk_gen; +struct F_EGsk_gen +{ + WORD regs[NREG-1]; + Keyring_EGsk** ret; + uchar temps[12]; + WORD nlen; + WORD nrep; +}; +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_iptob64z(void*); +typedef struct F_IPint_iptob64z F_IPint_iptob64z; +struct F_IPint_iptob64z +{ + 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_mod(void*); +typedef struct F_IPint_mod F_IPint_mod; +struct F_IPint_mod +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_IPint* i1; + Keyring_IPint* i2; +}; +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 IPint_not(void*); +typedef struct F_IPint_not F_IPint_not; +struct F_IPint_not +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_IPint* i1; +}; +void IPint_ori(void*); +typedef struct F_IPint_ori F_IPint_ori; +struct F_IPint_ori +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_IPint* i1; + Keyring_IPint* i2; +}; +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 Keyring_sha224(void*); +typedef struct F_Keyring_sha224 F_Keyring_sha224; +struct F_Keyring_sha224 +{ + WORD regs[NREG-1]; + Keyring_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Keyring_DigestState* state; +}; +void Keyring_sha256(void*); +typedef struct F_Keyring_sha256 F_Keyring_sha256; +struct F_Keyring_sha256 +{ + WORD regs[NREG-1]; + Keyring_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Keyring_DigestState* state; +}; +void Keyring_sha384(void*); +typedef struct F_Keyring_sha384 F_Keyring_sha384; +struct F_Keyring_sha384 +{ + WORD regs[NREG-1]; + Keyring_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Keyring_DigestState* state; +}; +void Keyring_sha512(void*); +typedef struct F_Keyring_sha512 F_Keyring_sha512; +struct F_Keyring_sha512 +{ + 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 RSAsk_sign(void*); +typedef struct F_RSAsk_sign F_RSAsk_sign; +struct F_RSAsk_sign +{ + WORD regs[NREG-1]; + Keyring_RSAsig** ret; + uchar temps[12]; + Keyring_RSAsk* k; + Keyring_IPint* m; +}; +void DSAsk_sign(void*); +typedef struct F_DSAsk_sign F_DSAsk_sign; +struct F_DSAsk_sign +{ + WORD regs[NREG-1]; + Keyring_DSAsig** ret; + uchar temps[12]; + Keyring_DSAsk* k; + Keyring_IPint* m; +}; +void EGsk_sign(void*); +typedef struct F_EGsk_sign F_EGsk_sign; +struct F_EGsk_sign +{ + WORD regs[NREG-1]; + Keyring_EGsig** ret; + uchar temps[12]; + Keyring_EGsk* k; + Keyring_IPint* m; +}; +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 RSApk_verify(void*); +typedef struct F_RSApk_verify F_RSApk_verify; +struct F_RSApk_verify +{ + WORD regs[NREG-1]; + WORD* ret; + uchar temps[12]; + Keyring_RSApk* k; + Keyring_RSAsig* sig; + Keyring_IPint* m; +}; +void DSApk_verify(void*); +typedef struct F_DSApk_verify F_DSApk_verify; +struct F_DSApk_verify +{ + WORD regs[NREG-1]; + WORD* ret; + uchar temps[12]; + Keyring_DSApk* k; + Keyring_DSAsig* sig; + Keyring_IPint* m; +}; +void EGpk_verify(void*); +typedef struct F_EGpk_verify F_EGpk_verify; +struct F_EGpk_verify +{ + WORD regs[NREG-1]; + WORD* ret; + uchar temps[12]; + Keyring_EGpk* k; + Keyring_EGsig* sig; + Keyring_IPint* m; +}; +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; +}; +void IPint_xor(void*); +typedef struct F_IPint_xor F_IPint_xor; +struct F_IPint_xor +{ + WORD regs[NREG-1]; + Keyring_IPint** ret; + uchar temps[12]; + Keyring_IPint* i1; + Keyring_IPint* i2; +}; +#define Keyring_PATH "$Keyring" +#define Keyring_SHA1dlen 20 +#define Keyring_SHA224dlen 28 +#define Keyring_SHA256dlen 32 +#define Keyring_SHA384dlen 48 +#define Keyring_SHA512dlen 64 +#define Keyring_MD5dlen 16 +#define Keyring_MD4dlen 16 +#define Keyring_Encrypt 0 +#define Keyring_Decrypt 1 +#define Keyring_AESbsize 16 +#define Keyring_DESbsize 8 +#define Keyring_IDEAbsize 8 +#define Keyring_BFbsize 8 diff --git a/libinterp/keyringif.m b/libinterp/keyringif.m new file mode 100644 index 0000000..8eed514 --- /dev/null +++ b/libinterp/keyringif.m @@ -0,0 +1,4 @@ +# temporary hack to prevent clashes with DigestState +include "sys.m"; + +include "keyring.m"; diff --git a/libinterp/link.c b/libinterp/link.c new file mode 100644 index 0000000..8775612 --- /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 0000000..2e3aa21 --- /dev/null +++ b/libinterp/load.c @@ -0,0 +1,621 @@ +#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); +} + +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 0000000..3de66c7 --- /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 0000000..f8391e1 --- /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 0000000..cae8dc4 --- /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 0000000..f15583f --- /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 0000000..8881dca --- /dev/null +++ b/libinterp/mkfile @@ -0,0 +1,129 @@ +<../mkconfig + +LIB=libinterp.a + +OFILES=\ + alt.$O\ + comp-$OBJTYPE.$O\ + conv.$O\ + crypt.$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\ + ../module/ipints.m\ + ../module/crypt.m\ + keyringif.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 keyringif.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 + +ipintsmod.h:D: $MODULES + rm -f $target && limbo -t IPints -I../module ../module/ipints.m > $target + +benchmod.h:D: ../module/bench.m + rm -f $target && limbo -t Bench -I../module ../module/bench.m > $target + +cryptmod.h:D: $MODULES + rm -f $target && limbo -t Crypt -I../module ../module/runt.m > $target + +keyringif.h:D: $MODULES keyringif.m + rm -f $target && limbo -a -I../module keyringif.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 ipint.h keyringif.h +crypt.$O: ipint.h runt.h cryptmod.h +ipint.$O: ipint.h ipintsmod.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 +comp-spim.c:N: comp-mips.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 cryptmod.h keyringif.h ipintsmod.h diff --git a/libinterp/mkoptab b/libinterp/mkoptab new file mode 100644 index 0000000..9b38b66 --- /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 0000000..e9a824f --- /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 0000000..086bedd --- /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 0000000..b7a9ad5 --- /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 0000000..eebc9ba --- /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 0000000..977d642 --- /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>=Runemax) + 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 0000000..a199759 --- /dev/null +++ b/libinterp/runt.h @@ -0,0 +1,4002 @@ +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 IPints_IPint IPints_IPint; +typedef struct Crypt_DigestState Crypt_DigestState; +typedef struct Crypt_AESstate Crypt_AESstate; +typedef struct Crypt_DESstate Crypt_DESstate; +typedef struct Crypt_IDEAstate Crypt_IDEAstate; +typedef struct Crypt_RC4state Crypt_RC4state; +typedef struct Crypt_BFstate Crypt_BFstate; +typedef struct Crypt_PK Crypt_PK; +typedef struct Crypt_SK Crypt_SK; +typedef struct Crypt_PKsig Crypt_PKsig; +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 IPints_IPint +{ + WORD x; +}; +#define IPints_IPint_size 4 +#define IPints_IPint_map {0} +struct Crypt_DigestState +{ + WORD x; +}; +#define Crypt_DigestState_size 4 +#define Crypt_DigestState_map {0} +struct Crypt_AESstate +{ + WORD x; +}; +#define Crypt_AESstate_size 4 +#define Crypt_AESstate_map {0} +struct Crypt_DESstate +{ + WORD x; +}; +#define Crypt_DESstate_size 4 +#define Crypt_DESstate_map {0} +struct Crypt_IDEAstate +{ + WORD x; +}; +#define Crypt_IDEAstate_size 4 +#define Crypt_IDEAstate_map {0} +struct Crypt_RC4state +{ + WORD x; +}; +#define Crypt_RC4state_size 4 +#define Crypt_RC4state_map {0} +struct Crypt_BFstate +{ + WORD x; +}; +#define Crypt_BFstate_size 4 +#define Crypt_BFstate_map {0} +#define Crypt_PK_RSA 0 +#define Crypt_PK_Elgamal 1 +#define Crypt_PK_DSA 2 +struct Crypt_PK +{ + int pick; + union{ + struct{ + IPints_IPint* n; + IPints_IPint* ek; + } RSA; + struct{ + IPints_IPint* p; + IPints_IPint* alpha; + IPints_IPint* key; + } Elgamal; + struct{ + IPints_IPint* p; + IPints_IPint* q; + IPints_IPint* alpha; + IPints_IPint* key; + } DSA; + } u; +}; +#define Crypt_PK_RSA_size 12 +#define Crypt_PK_RSA_map {0x60,} +#define Crypt_PK_Elgamal_size 16 +#define Crypt_PK_Elgamal_map {0x70,} +#define Crypt_PK_DSA_size 20 +#define Crypt_PK_DSA_map {0x78,} +#define Crypt_SK_RSA 0 +#define Crypt_SK_Elgamal 1 +#define Crypt_SK_DSA 2 +struct Crypt_SK +{ + int pick; + union{ + struct{ + Crypt_PK* pk; + IPints_IPint* dk; + IPints_IPint* p; + IPints_IPint* q; + IPints_IPint* kp; + IPints_IPint* kq; + IPints_IPint* c2; + } RSA; + struct{ + Crypt_PK* pk; + IPints_IPint* secret; + } Elgamal; + struct{ + Crypt_PK* pk; + IPints_IPint* secret; + } DSA; + } u; +}; +#define Crypt_SK_RSA_size 32 +#define Crypt_SK_RSA_map {0x7f,} +#define Crypt_SK_Elgamal_size 12 +#define Crypt_SK_Elgamal_map {0x60,} +#define Crypt_SK_DSA_size 12 +#define Crypt_SK_DSA_map {0x60,} +#define Crypt_PKsig_RSA 0 +#define Crypt_PKsig_Elgamal 1 +#define Crypt_PKsig_DSA 2 +struct Crypt_PKsig +{ + int pick; + union{ + struct{ + IPints_IPint* n; + } RSA; + struct{ + IPints_IPint* r; + IPints_IPint* s; + } Elgamal; + struct{ + IPints_IPint* r; + IPints_IPint* s; + } DSA; + } u; +}; +#define Crypt_PKsig_RSA_size 8 +#define Crypt_PKsig_RSA_map {0x40,} +#define Crypt_PKsig_Elgamal_size 12 +#define Crypt_PKsig_Elgamal_map {0x60,} +#define Crypt_PKsig_DSA_size 12 +#define Crypt_PKsig_DSA_map {0x60,} +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_readn(void*); +typedef struct F_Sys_readn F_Sys_readn; +struct F_Sys_readn +{ + 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 4 +#define Sys_UTFerror 65533 +#define Sys_Runemax 1114111 +#define Sys_Runemask 2097151 +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 IPints_DSAprimes(void*); +typedef struct F_IPints_DSAprimes F_IPints_DSAprimes; +struct F_IPints_DSAprimes +{ + WORD regs[NREG-1]; + struct{ IPints_IPint* t0; IPints_IPint* t1; Array* t2; }* ret; + uchar temps[12]; +}; +void IPint_add(void*); +typedef struct F_IPint_add F_IPint_add; +struct F_IPint_add +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_and(void*); +typedef struct F_IPint_and F_IPint_and; +struct F_IPint_and +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_b64toip(void*); +typedef struct F_IPint_b64toip F_IPint_b64toip; +struct F_IPint_b64toip +{ + WORD regs[NREG-1]; + IPints_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]; + IPints_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]; + IPints_IPint* i; +}; +void IPint_bytestoip(void*); +typedef struct F_IPint_bytestoip F_IPint_bytestoip; +struct F_IPint_bytestoip +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + Array* buf; +}; +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]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_copy(void*); +typedef struct F_IPint_copy F_IPint_copy; +struct F_IPint_copy +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i; +}; +void IPint_div(void*); +typedef struct F_IPint_div F_IPint_div; +struct F_IPint_div +{ + WORD regs[NREG-1]; + struct{ IPints_IPint* t0; IPints_IPint* t1; }* ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_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]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_expmod(void*); +typedef struct F_IPint_expmod F_IPint_expmod; +struct F_IPint_expmod +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* base; + IPints_IPint* exp; + IPints_IPint* mod; +}; +void IPints_genprime(void*); +typedef struct F_IPints_genprime F_IPints_genprime; +struct F_IPints_genprime +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + WORD nbits; + WORD nrep; +}; +void IPints_gensafeprime(void*); +typedef struct F_IPints_gensafeprime F_IPints_gensafeprime; +struct F_IPints_gensafeprime +{ + WORD regs[NREG-1]; + struct{ IPints_IPint* t0; IPints_IPint* t1; }* ret; + uchar temps[12]; + WORD nbits; + WORD nrep; +}; +void IPints_genstrongprime(void*); +typedef struct F_IPints_genstrongprime F_IPints_genstrongprime; +struct F_IPints_genstrongprime +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + WORD nbits; + WORD nrep; +}; +void IPint_inttoip(void*); +typedef struct F_IPint_inttoip F_IPint_inttoip; +struct F_IPint_inttoip +{ + WORD regs[NREG-1]; + IPints_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]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* base; + IPints_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]; + IPints_IPint* i; +}; +void IPint_iptob64z(void*); +typedef struct F_IPint_iptob64z F_IPint_iptob64z; +struct F_IPint_iptob64z +{ + WORD regs[NREG-1]; + String** ret; + uchar temps[12]; + IPints_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]; + IPints_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]; + IPints_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]; + IPints_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]; + IPints_IPint* i; + WORD base; +}; +void IPint_mod(void*); +typedef struct F_IPint_mod F_IPint_mod; +struct F_IPint_mod +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_mul(void*); +typedef struct F_IPint_mul F_IPint_mul; +struct F_IPint_mul +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_neg(void*); +typedef struct F_IPint_neg F_IPint_neg; +struct F_IPint_neg +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i; +}; +void IPint_not(void*); +typedef struct F_IPint_not F_IPint_not; +struct F_IPint_not +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; +}; +void IPint_ori(void*); +typedef struct F_IPint_ori F_IPint_ori; +struct F_IPint_ori +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPints_probably_prime(void*); +typedef struct F_IPints_probably_prime F_IPints_probably_prime; +struct F_IPints_probably_prime +{ + WORD regs[NREG-1]; + WORD* ret; + uchar temps[12]; + IPints_IPint* n; + WORD nrep; +}; +void IPint_random(void*); +typedef struct F_IPint_random F_IPint_random; +struct F_IPint_random +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + WORD nbits; +}; +void IPint_shl(void*); +typedef struct F_IPint_shl F_IPint_shl; +struct F_IPint_shl +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i; + WORD n; +}; +void IPint_shr(void*); +typedef struct F_IPint_shr F_IPint_shr; +struct F_IPint_shr +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i; + WORD n; +}; +void IPint_strtoip(void*); +typedef struct F_IPint_strtoip F_IPint_strtoip; +struct F_IPint_strtoip +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + String* str; + WORD base; +}; +void IPint_sub(void*); +typedef struct F_IPint_sub F_IPint_sub; +struct F_IPint_sub +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +void IPint_xor(void*); +typedef struct F_IPint_xor F_IPint_xor; +struct F_IPint_xor +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + IPints_IPint* i1; + IPints_IPint* i2; +}; +#define IPints_PATH "$IPints" +void Crypt_aescbc(void*); +typedef struct F_Crypt_aescbc F_Crypt_aescbc; +struct F_Crypt_aescbc +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_AESstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Crypt_aessetup(void*); +typedef struct F_Crypt_aessetup F_Crypt_aessetup; +struct F_Crypt_aessetup +{ + WORD regs[NREG-1]; + Crypt_AESstate** ret; + uchar temps[12]; + Array* key; + Array* ivec; +}; +void Crypt_blowfishcbc(void*); +typedef struct F_Crypt_blowfishcbc F_Crypt_blowfishcbc; +struct F_Crypt_blowfishcbc +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_BFstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Crypt_blowfishsetup(void*); +typedef struct F_Crypt_blowfishsetup F_Crypt_blowfishsetup; +struct F_Crypt_blowfishsetup +{ + WORD regs[NREG-1]; + Crypt_BFstate** ret; + uchar temps[12]; + Array* key; + Array* ivec; +}; +void DigestState_copy(void*); +typedef struct F_DigestState_copy F_DigestState_copy; +struct F_DigestState_copy +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Crypt_DigestState* d; +}; +void Crypt_descbc(void*); +typedef struct F_Crypt_descbc F_Crypt_descbc; +struct F_Crypt_descbc +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_DESstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Crypt_desecb(void*); +typedef struct F_Crypt_desecb F_Crypt_desecb; +struct F_Crypt_desecb +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_DESstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Crypt_dessetup(void*); +typedef struct F_Crypt_dessetup F_Crypt_dessetup; +struct F_Crypt_dessetup +{ + WORD regs[NREG-1]; + Crypt_DESstate** ret; + uchar temps[12]; + Array* key; + Array* ivec; +}; +void Crypt_dhparams(void*); +typedef struct F_Crypt_dhparams F_Crypt_dhparams; +struct F_Crypt_dhparams +{ + WORD regs[NREG-1]; + struct{ IPints_IPint* t0; IPints_IPint* t1; }* ret; + uchar temps[12]; + WORD nbits; +}; +void Crypt_dsagen(void*); +typedef struct F_Crypt_dsagen F_Crypt_dsagen; +struct F_Crypt_dsagen +{ + WORD regs[NREG-1]; + Crypt_SK** ret; + uchar temps[12]; + Crypt_PK* oldpk; +}; +void Crypt_eggen(void*); +typedef struct F_Crypt_eggen F_Crypt_eggen; +struct F_Crypt_eggen +{ + WORD regs[NREG-1]; + Crypt_SK** ret; + uchar temps[12]; + WORD nlen; + WORD nrep; +}; +void Crypt_genSK(void*); +typedef struct F_Crypt_genSK F_Crypt_genSK; +struct F_Crypt_genSK +{ + WORD regs[NREG-1]; + Crypt_SK** ret; + uchar temps[12]; + String* algname; + WORD length; +}; +void Crypt_genSKfromPK(void*); +typedef struct F_Crypt_genSKfromPK F_Crypt_genSKfromPK; +struct F_Crypt_genSKfromPK +{ + WORD regs[NREG-1]; + Crypt_SK** ret; + uchar temps[12]; + Crypt_PK* pk; +}; +void Crypt_hmac_md5(void*); +typedef struct F_Crypt_hmac_md5 F_Crypt_hmac_md5; +struct F_Crypt_hmac_md5 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* data; + WORD n; + Array* key; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_hmac_sha1(void*); +typedef struct F_Crypt_hmac_sha1 F_Crypt_hmac_sha1; +struct F_Crypt_hmac_sha1 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* data; + WORD n; + Array* key; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_ideacbc(void*); +typedef struct F_Crypt_ideacbc F_Crypt_ideacbc; +struct F_Crypt_ideacbc +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_IDEAstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Crypt_ideaecb(void*); +typedef struct F_Crypt_ideaecb F_Crypt_ideaecb; +struct F_Crypt_ideaecb +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_IDEAstate* state; + Array* buf; + WORD n; + WORD direction; +}; +void Crypt_ideasetup(void*); +typedef struct F_Crypt_ideasetup F_Crypt_ideasetup; +struct F_Crypt_ideasetup +{ + WORD regs[NREG-1]; + Crypt_IDEAstate** ret; + uchar temps[12]; + Array* key; + Array* ivec; +}; +void Crypt_md4(void*); +typedef struct F_Crypt_md4 F_Crypt_md4; +struct F_Crypt_md4 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_md5(void*); +typedef struct F_Crypt_md5 F_Crypt_md5; +struct F_Crypt_md5 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_rc4(void*); +typedef struct F_Crypt_rc4 F_Crypt_rc4; +struct F_Crypt_rc4 +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_RC4state* state; + Array* buf; + WORD n; +}; +void Crypt_rc4back(void*); +typedef struct F_Crypt_rc4back F_Crypt_rc4back; +struct F_Crypt_rc4back +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_RC4state* state; + WORD n; +}; +void Crypt_rc4setup(void*); +typedef struct F_Crypt_rc4setup F_Crypt_rc4setup; +struct F_Crypt_rc4setup +{ + WORD regs[NREG-1]; + Crypt_RC4state** ret; + uchar temps[12]; + Array* seed; +}; +void Crypt_rc4skip(void*); +typedef struct F_Crypt_rc4skip F_Crypt_rc4skip; +struct F_Crypt_rc4skip +{ + WORD regs[NREG-1]; + WORD noret; + uchar temps[12]; + Crypt_RC4state* state; + WORD n; +}; +void Crypt_rsadecrypt(void*); +typedef struct F_Crypt_rsadecrypt F_Crypt_rsadecrypt; +struct F_Crypt_rsadecrypt +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + Crypt_SK* k; + IPints_IPint* m; +}; +void Crypt_rsaencrypt(void*); +typedef struct F_Crypt_rsaencrypt F_Crypt_rsaencrypt; +struct F_Crypt_rsaencrypt +{ + WORD regs[NREG-1]; + IPints_IPint** ret; + uchar temps[12]; + Crypt_PK* k; + IPints_IPint* m; +}; +void Crypt_rsafill(void*); +typedef struct F_Crypt_rsafill F_Crypt_rsafill; +struct F_Crypt_rsafill +{ + WORD regs[NREG-1]; + Crypt_SK** ret; + uchar temps[12]; + IPints_IPint* n; + IPints_IPint* ek; + IPints_IPint* dk; + IPints_IPint* p; + IPints_IPint* q; +}; +void Crypt_rsagen(void*); +typedef struct F_Crypt_rsagen F_Crypt_rsagen; +struct F_Crypt_rsagen +{ + WORD regs[NREG-1]; + Crypt_SK** ret; + uchar temps[12]; + WORD nlen; + WORD elen; + WORD nrep; +}; +void Crypt_sha1(void*); +typedef struct F_Crypt_sha1 F_Crypt_sha1; +struct F_Crypt_sha1 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_sha224(void*); +typedef struct F_Crypt_sha224 F_Crypt_sha224; +struct F_Crypt_sha224 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_sha256(void*); +typedef struct F_Crypt_sha256 F_Crypt_sha256; +struct F_Crypt_sha256 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_sha384(void*); +typedef struct F_Crypt_sha384 F_Crypt_sha384; +struct F_Crypt_sha384 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_sha512(void*); +typedef struct F_Crypt_sha512 F_Crypt_sha512; +struct F_Crypt_sha512 +{ + WORD regs[NREG-1]; + Crypt_DigestState** ret; + uchar temps[12]; + Array* buf; + WORD n; + Array* digest; + Crypt_DigestState* state; +}; +void Crypt_sign(void*); +typedef struct F_Crypt_sign F_Crypt_sign; +struct F_Crypt_sign +{ + WORD regs[NREG-1]; + Crypt_PKsig** ret; + uchar temps[12]; + Crypt_SK* sk; + IPints_IPint* m; +}; +void Crypt_sktopk(void*); +typedef struct F_Crypt_sktopk F_Crypt_sktopk; +struct F_Crypt_sktopk +{ + WORD regs[NREG-1]; + Crypt_PK** ret; + uchar temps[12]; + Crypt_SK* sk; +}; +void Crypt_verify(void*); +typedef struct F_Crypt_verify F_Crypt_verify; +struct F_Crypt_verify +{ + WORD regs[NREG-1]; + WORD* ret; + uchar temps[12]; + Crypt_PK* pk; + Crypt_PKsig* sig; + IPints_IPint* m; +}; +#define Crypt_PATH "$Crypt" +#define Crypt_SHA1dlen 20 +#define Crypt_SHA224dlen 28 +#define Crypt_SHA256dlen 32 +#define Crypt_SHA384dlen 48 +#define Crypt_SHA512dlen 64 +#define Crypt_MD5dlen 16 +#define Crypt_MD4dlen 16 +#define Crypt_Encrypt 0 +#define Crypt_Decrypt 1 +#define Crypt_AESbsize 16 +#define Crypt_DESbsize 8 +#define Crypt_IDEAbsize 8 +#define Crypt_BFbsize 8 +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 diff --git a/libinterp/sign.c b/libinterp/sign.c new file mode 100644 index 0000000..950ad30 --- /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 0000000..037d1b4 --- /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 0000000..32320d5 --- /dev/null +++ b/libinterp/string.c @@ -0,0 +1,616 @@ +#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); + if(nc == 0) + return H; + ns = newrunes(nc); + memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune)); + } + else { + l = ds->len; + if(v < start || v > l) + error(exBounds); + if(nc == 0) + return H; + 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 0000000..f18e935 --- /dev/null +++ b/libinterp/sysmod.h @@ -0,0 +1,48 @@ +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,}, + "readn",0x7cfef557,Sys_readn,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 43 diff --git a/libinterp/tab.h b/libinterp/tab.h new file mode 100644 index 0000000..bc9dda1 --- /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 0000000..bf8fc8f --- /dev/null +++ b/libinterp/tk.c @@ -0,0 +1,1329 @@ +#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" + +#include "../emu/port/dat.h" +//#include "emu.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); + + t = (currun())->tktop; + if(t){ + poolmutable(D2H(t)); + *f->ret = (Tk_Toplevel*)t; + return; + } + + 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); + + { + Prog *p = currun(); + p->tktop = t; + t->prog = p; + } + + *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; + Point o; + int bd, flags, w, h; + + 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)); + if(flags & Tk_Required){ + h = tk->req.height; + w = tk->req.width; + }else{ + h = tk->act.height; + w = tk->act.width; + } + unlockctxt(t->ctxt); + if(w < 0) + w = 0; + if(h < 0) + h = 0; + bd = tk->borderwidth; + if(bd < 0) + bd = 0; + if(flags & Tk_Border){ + r.min = o; + r.max.x = r.min.x + w + bd + bd; + r.max.y = r.min.y + h + bd + bd; + }else{ + r.min.x = o.x + bd; + r.min.y = o.y + bd; + r.max.x = r.min.x + w; + r.max.y = r.min.y + h; + } + *(Rectangle*)f->ret = r; +} + +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); + 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); + } + if(t->prog){ + Prog* p = t->prog; + t->prog = nil; + p->tktop = nil; + } +} + +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 0000000..0b8b97a --- /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 0000000..6956a64 --- /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 0000000..29778c0 --- /dev/null +++ b/libinterp/xec.c @@ -0,0 +1,1698 @@ +#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 = malloc(sizeof(Progq)); + c->recv = 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; + Heap *h; + + 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; + h = D2H(ml->MP); + h->ref++; + Setmark(h); + } + } + 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; + Heap *h; + + ml = R.M; + h = D2H(ml); + h->ref++; + Setmark(h); + 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; +} |
