summaryrefslogtreecommitdiff
path: root/sys/src/cmd/1l
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/1l
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/1l')
-rwxr-xr-xsys/src/cmd/1l/asm.c1529
-rwxr-xr-xsys/src/cmd/1l/compat.c50
-rwxr-xr-xsys/src/cmd/1l/cputime.c12
-rwxr-xr-xsys/src/cmd/1l/l.h271
-rwxr-xr-xsys/src/cmd/1l/list.c334
-rwxr-xr-xsys/src/cmd/1l/mkfile22
-rwxr-xr-xsys/src/cmd/1l/obj.c1413
-rwxr-xr-xsys/src/cmd/1l/optab.c444
-rwxr-xr-xsys/src/cmd/1l/pass.c673
-rwxr-xr-xsys/src/cmd/1l/span.c515
10 files changed, 5263 insertions, 0 deletions
diff --git a/sys/src/cmd/1l/asm.c b/sys/src/cmd/1l/asm.c
new file mode 100755
index 000000000..6cf02ed8c
--- /dev/null
+++ b/sys/src/cmd/1l/asm.c
@@ -0,0 +1,1529 @@
+#include "l.h"
+
+short opa[20];
+short *op;
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long v;
+ int a;
+ short *op1;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ curp = firstp;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->pc != pc) {
+ if(!debug['a'])
+ print("%P\n", curp);
+ diag("phase error %.4lux sb %.4lux in %s", p->pc, pc, TNAME);
+ pc = p->pc;
+ }
+ curp = p;
+ if(debug['a'])
+ Bprint(&bso, "%lux:%P\n", pc, curp);
+ asmins(p);
+ if(cbc < sizeof(opa))
+ cflush();
+ for(op1 = opa; op1 < op; op1++) {
+ a = *op1;
+ *cbp++ = a >> 8;
+ *cbp++ = a;
+ }
+ a = 2*(op - opa);
+ pc += a;
+ cbc -= a;
+ if(debug['a']) {
+ for(op1 = opa; op1 < op; op1++)
+ if(op1 == opa)
+ Bprint(&bso, "\t\t%4ux", *op1 & 0xffff);
+ else
+ Bprint(&bso, " %4ux", *op1 & 0xffff);
+ if(op != opa)
+ Bprint(&bso, "\n");
+ }
+ }
+ cflush();
+ switch(HEADTYPE) {
+ case 0: /* this is garbage */
+ seek(cout, rnd(HEADR+textsize, 8192), 0);
+ break;
+ case 1: /* plan9 boot data goes into text */
+ seek(cout, rnd(HEADR+textsize, INITRND), 0);
+ break;
+ case 2: /* plan 9 */
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 3: /* next boot */
+ seek(cout, HEADR+rnd(textsize, INITRND), 0);
+ break;
+ case 4: /* preprocess pilot */
+ seek(cout, HEADR+textsize, 0);
+ break;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ for(v = 0; v < datsize; v += sizeof(buf)-100) {
+ if(datsize-v > sizeof(buf)-100)
+ datblk(v, sizeof(buf)-100);
+ else
+ datblk(v, datsize-v);
+ }
+
+ symsize = 0;
+ spsize = 0;
+ lcsize = 0;
+ relocsize = 0;
+
+ Bflush(&bso);
+
+ switch(HEADTYPE) {
+ default:
+ seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ break;
+ case 1: /* plan9 boot data goes into text */
+ seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ break;
+ case 2: /* plan 9 */
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 3: /* next boot */
+ seek(cout, HEADR+rnd(textsize, INITRND)+datsize, 0);
+ break;
+ case 4: /* preprocess pilot */
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ }
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ asmsym();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ asmsp();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ asmlc();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ asmreloc();
+ }
+ cflush();
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ default:
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lput((0413<<16)|0437L); /* magic and version */
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT-HEADR); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ break;
+ case 1: /* plan9 boot data goes into text */
+ lput(0407); /* magic */
+ lput(rnd(HEADR+textsize, INITRND)-HEADR+datsize); /* sizes */
+ lput(0);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 2: /* plan 9 */
+ lput(0407); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 3: /* next boot */
+ /* header */
+ lput(0xfeedfaceL); /* magic */
+ lput(6); /* 68040 */
+ lput(1); /* more 68040 */
+ lput(5); /* file type 'boot' */
+ lput(HEADTYPE); /* number commands */
+ lput(HEADR-7*4); /* sizeof commands */
+ lput(1); /* no undefineds */
+ /* command 1 text */
+ lput(1); /* command = 'segment' */
+ lput(124); /* command size */
+ s16put("__TEXT");
+ /* botch?? entryvalue() */
+ lput(INITTEXT); /* va of start */
+ lput(rnd(textsize, 8192)); /* va size */
+ lput(HEADR); /* file offset */
+ lput(rnd(textsize, 8192)); /* file size */
+ lput(7); /* max prot */
+ lput(7); /* init prot */
+ lput(1); /* number of sections */
+ lput(0); /* flags */
+ /* text section */
+ s16put("__text");
+ s16put("__TEXT");
+ /* botch?? entryvalue() */
+ lput(INITTEXT); /* va of start */
+ lput(textsize); /* va size */
+ lput(HEADR); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(0); /* flags */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* command 1 data */
+ lput(1); /* command = 'segment' */
+ lput(192); /* command size */
+ s16put("__DATA");
+ lput(INITDAT); /* va of start */
+ lput(rnd(datsize, 8192)); /* va size */
+ lput(HEADR+rnd(textsize, 8192)); /* file offset */
+ lput(rnd(datsize, 8192)); /* file size */
+ lput(7); /* max prot */
+ lput(7); /* init prot */
+ lput(2); /* number of sections */
+ lput(0); /* flags */
+ /* data section */
+ s16put("__data");
+ s16put("__DATA");
+ lput(INITDAT); /* va of start */
+ lput(datsize); /* va size */
+ lput(HEADR+rnd(textsize, 8192)); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(0); /* flags */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* bss section */
+ s16put("__bss");
+ s16put("__DATA");
+ lput(INITDAT+datsize); /* va of start */
+ lput(bsssize); /* va size */
+ lput(0); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(1); /* flags = zero fill */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* command 2 symbol */
+ lput(2); /* command = 'symbol' */
+ lput(24); /* command size */
+ lput(HEADR+rnd(textsize, INITRND)
+ +datsize); /* symoff */
+ lput(symsize); /* nsyms */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 4: /* preprocess pilot */
+ lput(0407); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ lput(relocsize); /* relocation */
+ break;
+ }
+ cflush();
+}
+
+void
+asmins(Prog *p)
+{
+ Optab *o;
+ int t, a, b;
+ long v;
+
+ op = opa + 1;
+ if(special[p->from.type])
+ switch(p->from.type) {
+
+ case D_CCR:
+ if(p->as != AMOVW)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x42c0 | a; /* mov from ccr */
+ return;
+
+ case D_SR:
+ if(p->as != AMOVW)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x40c0 | a; /* mov from sr */
+ return;
+
+ case D_USP:
+ if(p->as != AMOVL)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010) {
+ opa[0] = 0x4e68|(a&7); /* mov usp An */
+ return;
+ }
+ t = 0x800;
+ goto movec1;
+
+ case D_SFC:
+ t = 0x000;
+ goto movec1;
+
+ case D_DFC:
+ t = 0x001;
+ goto movec1;
+
+ case D_CACR:
+ t = 0x002;
+ goto movec1;
+
+ case D_TC:
+ t = 0x003;
+ goto movec1;
+
+ case D_ITT0:
+ t = 0x004;
+ goto movec1;
+
+ case D_ITT1:
+ t = 0x005;
+ goto movec1;
+
+ case D_DTT0:
+ t = 0x006;
+ goto movec1;
+
+ case D_DTT1:
+ t = 0x007;
+ goto movec1;
+
+ case D_VBR:
+ t = 0x801;
+ goto movec1;
+
+ case D_CAAR:
+ t = 0x802;
+ goto movec1;
+
+ case D_MSP:
+ t = 0x803;
+ goto movec1;
+
+ case D_ISP:
+ t = 0x804;
+ goto movec1;
+
+ case D_MMUSR:
+ t = 0x805;
+ goto movec1;
+
+ case D_URP:
+ t = 0x806;
+ goto movec1;
+
+ case D_SRP:
+ t = 0x807;
+ goto movec1;
+
+ movec1:
+ if(p->as != AMOVL)
+ goto bad;
+ opa[0] = 0x4e7a; /* mov spc Dn */
+ a = asmea(p, &p->to);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ *op++ = (a<<12) | t;
+ return;
+ }
+ goto bad;
+
+ case D_FPCR:
+ t = 0xb000;
+ goto movec3;
+
+ case D_FPSR:
+ t = 0xa800;
+ goto movec3;
+
+ case D_FPIAR:
+ t = 0xa400;
+
+ movec3:
+ if(p->as != AMOVL)
+ goto bad;
+ op++;
+ a = asmea(p, &p->to);
+ opa[0] = optab[AFMOVEL].opcode0 | a;
+ opa[1] = t;
+ return;
+ }
+ if(special[p->to.type])
+ switch(p->to.type) {
+
+ case D_CCR:
+ if(p->as != AMOVW) /* botch, needs and, eor etc. */
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x44c0 | a; /* mov to ccr */
+ return;
+
+ case D_SR:
+ if(p->as != AMOVW) /* botch, needs and, eor etc. */
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x46c0 | a; /* mov to sr */
+ return;
+
+ case D_USP:
+ if(p->as != AMOVL)
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010) {
+ opa[0] = 0x4e60|(a&7); /* mov An usp */
+ return;
+ }
+ t = 0x800;
+ goto movec2;
+
+ case D_SFC:
+ t = 0x000;
+ goto movec2;
+
+ case D_DFC:
+ t = 0x001;
+ goto movec2;
+
+ case D_CACR:
+ t = 0x002;
+ goto movec2;
+
+ case D_TC:
+ t = 0x003;
+ goto movec2;
+
+ case D_ITT0:
+ t = 0x004;
+ goto movec2;
+
+ case D_ITT1:
+ t = 0x005;
+ goto movec2;
+
+ case D_DTT0:
+ t = 0x006;
+ goto movec2;
+
+ case D_DTT1:
+ t = 0x007;
+ goto movec2;
+
+ case D_VBR:
+ t = 0x801;
+ goto movec2;
+
+ case D_CAAR:
+ t = 0x802;
+ goto movec2;
+
+ case D_MSP:
+ t = 0x803;
+ goto movec2;
+
+ case D_ISP:
+ t = 0x804;
+ goto movec2;
+
+ case D_MMUSR:
+ t = 0x805;
+ goto movec2;
+
+ case D_URP:
+ t = 0x806;
+ goto movec2;
+
+ case D_SRP:
+ t = 0x807;
+ goto movec2;
+
+ movec2:
+ if(p->as != AMOVL)
+ goto bad;
+ opa[0] = 0x4e7b; /* mov Dn spc */
+ a = asmea(p, &p->from);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ *op++ = (a<<12) | t;
+ return;
+ }
+ goto bad;
+
+ case D_FPCR:
+ t = 0x9000;
+ goto movec4;
+
+ case D_FPSR:
+ t = 0x8800;
+ goto movec4;
+
+ case D_FPIAR:
+ t = 0x8400;
+
+ movec4:
+ if(p->as != AMOVL)
+ goto bad;
+ op++;
+ a = asmea(p, &p->from);
+ opa[0] = optab[AFMOVEL].opcode0 | a;
+ opa[1] = t;
+ return;
+ }
+
+ o = &optab[p->as];
+ t = o->opcode0;
+ switch(o->optype) {
+ case 0: /* pseudo ops */
+ if(p->as != ATEXT && p->as != ANOP) {
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("unimplemented instruction in %s", TNAME);
+ return;
+ }
+ op = opa;
+ return;
+
+ case 1: /* branches */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ a = asmea(p, &p->to);
+ if(a == 071)
+ t = o->opcode1;
+ t |= a;
+ break;
+
+ case 2: /* move */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0110) { /* src quick */
+ t = o->opcode1;
+ if((b & 0170) != 0)
+ goto bad;
+ t |= a >> 7;
+ t |= b << 9;
+ break;
+ }
+ t |= a;
+ t |= (b&7) << 9;
+ t |= (b&070) << 3;
+ break;
+
+ case 3: /* add */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0110) { /* src quick */
+ t = o->opcode1;
+ t |= (a&01600) << 2;
+ t |= b;
+ break;
+ }
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+ }
+ if((b & 0170) == 010) { /* dst An */
+ if((t & 0xc0) == 0)
+ goto bad;
+ t = o->opcode2;
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t |= 0x100;
+ t |= (a & 7) << 9;
+ t |= b;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode3;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 4: /* no operands */
+ break;
+
+ case 5: /* tst */
+ t |= asmea(p, &p->to);
+ if((t&0170) == 010)
+ goto bad;
+ break;
+
+ case 6: /* lea */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) != 010)
+ goto bad;
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+
+ case 7: /* cmp */
+ b = asmea(p, &p->to);
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010) { /* dst An */
+ t = o->opcode1;
+ if(t == 0) /* cmpb illegal */
+ goto bad;
+ t |= 0xc0;
+ t |= b;
+ t |= (a & 7) << 9;
+ break;
+ }
+ if((b & 0177) == 074) { /* src immed */
+ t = o->opcode2;
+ t |= a;
+ break;
+ }
+ if((a & 0170) == 0) { /* dst Dn */
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((b&0170) == 030 && (a&0170) == 030) { /* (A)+,(A)+ */
+ t = o->opcode3;
+ t |= b & 7;
+ t |= (a & 7) << 9;
+ break;
+ }
+ goto bad;
+
+ case 8: /* svc */
+ *op++ = optab[ARTS].opcode0;
+ break;
+
+ case 9: /* and */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= a;
+ t |= (b&7) << 9;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t = o->opcode1;
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode2;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 10: /* eor */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ if((a & 0170) == 0) { /* src Dn */
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode1;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 11: /* ext */
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 12: /* shift */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0177) == 0110) { /* src quick */
+ t |= (a & 01600) << 2;
+ t |= b;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t |= 0x20;
+ t |= a << 9;
+ t |= b;
+ break;
+ }
+ goto bad;
+ }
+ goto bad;
+
+ case 13: /* mul, div short */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0170) == 010)
+ goto bad;
+ t |= a;
+ t |= b << 9;
+ break;
+ }
+ goto bad;
+
+ case 14: /* mul, div long */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0170) == 010)
+ goto bad;
+ t |= a;
+ opa[1] |= b << 12;
+ opa[1] |= b+1;
+ break;
+ }
+ goto bad;
+
+ case 15: /* dec and branch */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ a = asmea(p, &p->from);
+ if((a & 0170) != 0)
+ goto bad;
+ t |= a;
+ break;
+
+ case 16: /* fmove */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0100) { /* src Fn */
+ if((b & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= b;
+ opa[1] = o->opcode2;
+ opa[1] |= (a&7) << 7;
+ break;
+ }
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ t |= a;
+ opa[1] = o->opcode3;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 17: /* floating ea,Fn */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((a & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 18: /* floating branchs */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ break;
+
+ case 19: /* floating dec and branch */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ *op++ = o->opcode1;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ a = asmea(p, &p->from);
+ if((a & 0170) != 0)
+ goto bad;
+ t |= a;
+ break;
+
+ case 20: /* ftst ea */
+ *op++ = o->opcode1;
+ if(p->from.type != D_NONE)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 0100) { /* Fn */
+ opa[1] |= (a&7) << 10;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ break;
+
+ case 21: /* fneg */
+ *op++ = o->opcode1;
+ if(p->from.type == D_NONE) {
+ b = asmea(p, &p->to);
+ a = b;
+ } else {
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ }
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((a & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 22: /* floating cmp Fn,ea */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((b & 0170) == 0100) { /* both Fn */
+ opa[1] |= (b&7) << 10;
+ opa[1] |= (a&7) << 7;
+ break;
+ }
+ t |= b;
+ opa[1] = o->opcode2;
+ opa[1] |= (a&7) << 7;
+ break;
+
+ case 23: /* word, long */
+ op = opa;
+ a = asmea(p, &p->to);
+ if(a == ((7<<3)|4))
+ return;
+ if(a == ((7<<3)|1)) {
+ if(p->as == AWORD) {
+ op = opa;
+ *op++ = opa[1];
+ }
+ return;
+ }
+ if(a == ((7<<3)|0)) {
+ if(p->as == ALONG) {
+ *op++ = opa[0];
+ opa[0] = 0;
+ }
+ return;
+ }
+ goto bad;
+
+ case 24: /* bit field */
+ a = ((p->to.field&31)<<6) | (p->from.field&31);
+ if(p->as == ABFINS) {
+ b = asmea(p, &p->from);
+ if((b&0170) != 0)
+ goto bad;
+ a |= b<<12;
+ *op++ = a;
+ a = asmea(p, &p->to);
+ } else {
+ if(p->to.type != D_NONE) {
+ b = asmea(p, &p->to);
+ if((b&0170) != 0)
+ goto bad;
+ a |= b<<12;
+ }
+ *op++ = a;
+ a = asmea(p, &p->from);
+ }
+ t |= a;
+ a &= 0170;
+ if(a == 010 || a == 030 || a == 040 || a == 074)
+ goto bad;
+ break;
+
+ case 25: /* movem */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ asmea(p, &p->from);
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ t |= 0x400;
+ asmea(p, &p->to);
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 26: /* chk */
+ a = asmea(p, &p->from);
+ if((a&0170) == 010)
+ goto bad;
+ b = asmea(p, &p->to);
+ if((b&0170) != 0)
+ goto bad;
+ t |= a;
+ t |= b<<9;
+ break;
+
+ case 27: /* btst */
+ a = asmea(p, &p->from);
+ if(a == 074) {
+ t = o->opcode1;
+ } else
+ if((a&0170) != 0)
+ goto bad;
+ b = asmea(p, &p->to);
+ if(b == 074 || (b&0170) == 010)
+ goto bad;
+ t |= b;
+ break;
+
+ case 28: /* fmovem */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ b = p->from.offset & 0xff;
+ b |= 0xf000; /* control or postinc */
+ *op++ = b;
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ if(b == 040)
+ op[-1] &= ~0x1000; /* predec */
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ b = p->to.offset & 0xff;
+ b |= 0xd000; /* control or postinc */
+ *op++ = b;
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 29: /* fmovemc */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ b = (p->from.offset & 0x7) << 10;
+ b |= 0xa000;
+ *op++ = b;
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ b = (p->to.offset & 0x7) << 10;
+ b |= 0x8000;
+ *op++ = b;
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 30: /* trap */
+ if(p->to.type == D_CONST) {
+ t |= p->to.offset & 0xf;
+ break;
+ }
+ goto bad;
+
+ case 31: /* chk2, cmp2 */
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a == 000 || a == 010) {
+ *op++ = o->opcode1 | (b << 12);
+ t |= asmea(p, &p->from);
+ break;
+ }
+ goto bad;
+
+ case 32: /* casew */
+ /* jmp (0,pc,r0.w*1) */
+ casepc = p->pc;
+ *op++ = o->opcode1;
+ break;
+
+ case 34: /* moves */
+ op++;
+ a = asmea(p, &p->from);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ opa[1] = (a << 12) | 0x800;
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a == 0 || a == 010)
+ goto bad;
+ t |= b;
+ break;
+ }
+ t |= a;
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a != 0 && a != 010)
+ goto bad;
+ opa[1] = (b << 12);
+ break;
+
+ case 35: /* swap */
+ a = asmea(p, &p->to);
+ if((a & 0170) == 0) {
+ t |= a;
+ break;
+ }
+ goto bad;
+ }
+ opa[0] = t;
+ return;
+
+bad:
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("bad combination of addressing in %s", TNAME);
+ opa[0] = 0;
+}
+
+int
+asmea(Prog *p, Adr *a)
+{
+ Optab *o;
+ int f, t, r, i;
+ long v;
+
+ t = a->type;
+ r = simple[t];
+ v = a->offset;
+ if(r != 0177) {
+ if(v == 0)
+ return r;
+ if((r & 070) != 020)
+ return r;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return t-D_A0-I_INDIR+050; /* d(Ax) */
+ }
+ goto toobig;
+ }
+ f = 0;
+ if(a == &p->from)
+ f++;
+ o = &optab[p->as];
+ switch(t) {
+ case D_TOS:
+ if(f) {
+ if(o->srcsp)
+ return (3<<3) | 7; /* (A7)+ */
+ } else
+ if(o->dstsp)
+ return (4<<3) | 7; /* -(A7) */
+ return (2<<3) | 7; /* (A7) */
+
+ case D_BRANCH:
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L) {
+ if(p->as == ABSR || p->as == ABRA) {
+ v = p->pcond->pc;
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ goto toobig;
+ }
+ if(v < -128 || v >= 128 || p->mark == 4) {
+ *op++ = v;
+ return 0;
+ }
+ return v & 0xff;
+
+ case I_ADDR|D_STATIC:
+ case I_ADDR|D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ v = a->sym->value + a->offset;
+ if(t != STEXT)
+ v += INITDAT;
+ if(strcmp(a->sym->name, "a6base"))
+ break;
+
+ case D_CONST:
+ switch(f? o->srcsp: o->dstsp) {
+ case 4:
+ *op++ = v>>16;
+
+ case 2:
+ *op++ = v;
+ break;
+
+ default:
+ diag("unknown srcsp asmea in %s", TNAME);
+ }
+ return (7<<3) | 4;
+
+ case D_FCONST:
+ r = f? o->srcsp: o->dstsp;
+ for(i=0; i<r; i++)
+ ((char*)op)[i] = gnuxi(&a->ieee, i, r);
+ op += r/2;
+ return (7<<3) | 4;
+
+ case D_QUICK:
+ v = a->offset & 0xff;
+ return 0110 | (v<<7);
+
+ case D_STACK:
+ case D_AUTO:
+ case D_PARAM:
+ if(v == 0)
+ return (2<<3) | 7; /* (A7) */
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (5<<3) | 7; /* d(A7) */
+ }
+ goto toobig;
+
+ case I_INDIR|D_CONST:
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 0;
+ }
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+
+ case D_STATIC:
+ case D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ if(t == STEXT) {
+ if(HEADTYPE == 4) {
+ v = a->sym->value + a->offset - p->pc - 2;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 2;
+ }
+ goto toobig;
+ }
+ v = a->sym->value + a->offset;
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ v = a->sym->value + a->offset - A6OFFSET;
+ if(v < -32768L || v >= 32768L) {
+ v += INITDAT + A6OFFSET;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 0;
+ }
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ if(v == 0)
+ return (2<<3) | 6;
+ *op++ = v;
+ return (5<<3) | 6;
+ }
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("unknown addressing mode: %d in %s", t, TNAME);
+ return 0;
+
+toobig:
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("addressing mode >> 2^16: %d in %s", t, TNAME);
+ return 0;
+}
+
+void
+lput(long l)
+{
+
+ CPUT(l>>24)
+ CPUT(l>>16)
+ CPUT(l>>8)
+ CPUT(l)
+}
+
+void
+s16put(char *n)
+{
+ char name[16];
+ int i;
+
+ strncpy(name, n, sizeof(name));
+ for(i=0; i<sizeof(name); i++)
+ CPUT(name[i])
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->from.displace;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ switch(p->to.type) {
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (char*)&fl;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j+4]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i+4]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.scon[i];
+ l++;
+ }
+ break;
+ default:
+ fl = p->to.offset;
+ if(p->to.sym) {
+ if(p->to.sym->type == STEXT)
+ fl += p->to.sym->value;
+ if(p->to.sym->type == SDATA)
+ fl += p->to.sym->value + INITDAT;
+ if(p->to.sym->type == SBSS)
+ fl += p->to.sym->value + INITDAT;
+ }
+
+ cast = (char*)&fl;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi1[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi2[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi4[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+void
+asmreloc(void)
+{
+ Prog *p;
+ Sym *s1, *s2;
+ int c1, c2, c3;
+ long v;
+
+ if(HEADTYPE != 4)
+ return;
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ s1 = p->to.sym;
+ if(s1 == S)
+ continue;
+ c1 = 'D';
+ c3 = p->from.displace;
+ s2 = p->from.sym;
+ v = s2->value + INITDAT;
+ switch(s1->type) {
+ default:
+ diag("unknown reloc %d", s1->type);
+ continue;
+ case STEXT:
+ c2 = 'T';
+ break;
+
+ case SDATA:
+ c2 = 'D';
+ break;
+
+ case SBSS:
+ c2 = 'B';
+ break;
+ }
+ CPUT(c1);
+ CPUT(c2);
+ CPUT(c3);
+ lput(v);
+ if(debug['a'])
+ Bprint(&bso, "r %c%c%d %.8lux %s $%s\n",
+ c1, c2, c3, v, s2->name, s1->name);
+ relocsize += 7;
+ }
+}
+
+int
+gnuxi(Ieee *d, int i, int c)
+{
+ char *p;
+ long l;
+
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ return 0;
+
+ /*
+ * 2301 vax
+ * 0123 68k
+ */
+ case 4:
+ l = ieeedtof(d);
+ p = (char*)&l;
+ i = gnuxi8[i+4];
+ break;
+
+ /*
+ * 67452301 vax
+ * 45670123 68k
+ */
+ case 8:
+ p = (char*)d;
+ i = gnuxi8[i];
+ break;
+ }
+ return p[i];
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/sys/src/cmd/1l/compat.c b/sys/src/cmd/1l/compat.c
new file mode 100755
index 000000000..d01de9b3f
--- /dev/null
+++ b/sys/src/cmd/1l/compat.c
@@ -0,0 +1,50 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ fprint(2, "realloc(0x%p, %ld) called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
diff --git a/sys/src/cmd/1l/cputime.c b/sys/src/cmd/1l/cputime.c
new file mode 100755
index 000000000..3ef54a10e
--- /dev/null
+++ b/sys/src/cmd/1l/cputime.c
@@ -0,0 +1,12 @@
+double
+cputime(void)
+{
+ long t[4];
+ long times(long*);
+ int i;
+
+ times(t);
+ for(i=1; i<4; i++)
+ t[0] += t[i];
+ return t[0] / 100.;
+}
diff --git a/sys/src/cmd/1l/l.h b/sys/src/cmd/1l/l.h
new file mode 100755
index 000000000..41ec65685
--- /dev/null
+++ b/sys/src/cmd/1l/l.h
@@ -0,0 +1,271 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "../2c/2.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext?curtext->from.sym->name:noname)
+#define CPUT(c)\
+ { *cbp++ = c;\
+ if(--cbc <= 0)\
+ cflush(); }
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+
+struct Adr
+{
+ short type;
+ uchar field;
+ union
+ {
+ struct
+ {
+ long u0displace;
+ long u0offset;
+ } s0;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+};
+
+#define displace u0.s0.u0displace
+#define offset u0.s0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0stkoff;
+ Prog *u0forwd;
+ } u0;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ long pc;
+ long line;
+ short as;
+ uchar mark; /* work on these */
+ uchar back;
+};
+
+#define stkoff u0.u0stkoff
+#define forwd u0.u0forwd
+
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ long value;
+ Sym* link;
+};
+struct Optab
+{
+ short as;
+ short fas;
+ short srcsp;
+ short dstsp;
+ ushort optype;
+ ushort opcode0;
+ ushort opcode1;
+ ushort opcode2;
+ ushort opcode3;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SAUTO,
+ SPARAM,
+ SFILE,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 4,
+ STRINGSZ = 200,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ A6OFFSET = 32766,
+};
+
+EXTERN union
+{
+ struct
+ {
+ char obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+#pragma varargck argpos diag 1
+
+EXTERN long HEADR;
+EXTERN long HEADTYPE;
+EXTERN long INITDAT;
+EXTERN long INITRND;
+EXTERN long INITTEXT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN long casepc;
+EXTERN int cbc;
+EXTERN char* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN Prog* prog_divsl;
+EXTERN Prog* prog_divul;
+EXTERN Prog* prog_mull;
+EXTERN Prog* prog_ccr;
+EXTERN char fnuxi8[8];
+EXTERN char gnuxi8[8];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN long relocsize;
+EXTERN long ndata;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long nsymbol;
+EXTERN char* noname;
+EXTERN short* op;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN char simple[I_MASK];
+EXTERN char special[I_MASK];
+EXTERN long spsize;
+EXTERN Sym* symlist;
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN Prog zprg;
+
+extern Optab optab[];
+extern char mmsize[];
+extern char* anames[];
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+int Xconv(Fmt*);
+void addhist(long, int);
+int andsize(Prog*, Adr*);
+void asmb(void);
+int asmea(Prog*, Adr*);
+void asmins(Prog*);
+void asmlc(void);
+void asmsp(void);
+void asmsym(void);
+void asmreloc(void);
+long atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void cflush(void);
+Prog* copyp(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+long entryvalue(void);
+void errorexit(void);
+int find1(long, int);
+int find2(long, int);
+void follow(void);
+void gethunk(void);
+int gnuxi(Ieee*, int, int);
+void histtoauto(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void initmuldiv1(void);
+void initmuldiv2(void);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void main(int, char*[]);
+void mkfwd(void);
+void* mysbrk(ulong);
+void nuxiinit(void);
+void objfile(char*);
+void patch(void);
+Prog* prg(void);
+Prog* nprg(Prog*);
+int relinv(int);
+long reuse(Prog*, Sym*);
+long rnd(long, long);
+void s16put(char*);
+void span(void);
+void undef(void);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+int zaddr(uchar*, Adr*, Sym*[]);
diff --git a/sys/src/cmd/1l/list.c b/sys/src/cmd/1l/list.c
new file mode 100755
index 000000000..f02c3efa7
--- /dev/null
+++ b/sys/src/cmd/1l/list.c
@@ -0,0 +1,334 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+}
+
+static Prog *bigP;
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[20];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ sprint(str, "(%ld) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ if(p->from.field) {
+ sprint(s, ",%d,%d", p->to.field, p->from.field);
+ strcat(str, s);
+ }
+ bigP = P;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+
+ return fmtstrcpy(fp, anames[va_arg(fp->args, int)]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i, j;
+ long d;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ j = i & I_MASK;
+ if(j) {
+ a->type = i & D_MASK;
+ d = a->offset;
+ a->offset = 0;
+ switch(j) {
+ case I_INDINC:
+ sprint(str, "(%D)+", a);
+ break;
+
+ case I_INDDEC:
+ sprint(str, "-(%D)", a);
+ break;
+
+ case I_INDIR:
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_ADDR:
+ a->offset = d;
+ sprint(str, "$%D", a);
+ break;
+ }
+ a->type = i;
+ a->offset = d;
+ goto out;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ sprint(str, "%lux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ sprint(str, "%lux", bigP->pcond->pc);
+ else
+ sprint(str, "%ld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<%d>+%ld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_STACK:
+ sprint(str, "TOS+%ld", a->offset);
+ break;
+
+ case D_QUICK:
+ sprint(str, "$Q%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ goto out;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->scon);
+ goto out;
+ }
+ if(a->displace) {
+ sprint(s, "/%ld", a->displace);
+ strcat(str, s);
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_R0 && r < D_R0+NREG)
+ sprint(str, "R%d", r-D_R0);
+ else
+ if(r >= D_A0 && r < D_A0+NREG)
+ sprint(str, "A%d", r-D_A0);
+ else
+ if(r >= D_F0 && r < D_F0+NREG)
+ sprint(str, "F%d", r-D_F0);
+ else
+ switch(r) {
+
+ default:
+ sprint(str, "gok(%d)", r);
+ break;
+
+ case D_NONE:
+ sprint(str, "NONE");
+ break;
+
+ case D_TOS:
+ sprint(str, "TOS");
+ break;
+
+ case D_CCR:
+ sprint(str, "CCR");
+ break;
+
+ case D_SR:
+ sprint(str, "SR");
+ break;
+
+ case D_SFC:
+ sprint(str, "SFC");
+ break;
+
+ case D_DFC:
+ sprint(str, "DFC");
+ break;
+
+ case D_CACR:
+ sprint(str, "CACR");
+ break;
+
+ case D_USP:
+ sprint(str, "USP");
+ break;
+
+ case D_VBR:
+ sprint(str, "VBR");
+ break;
+
+ case D_CAAR:
+ sprint(str, "CAAR");
+ break;
+
+ case D_MSP:
+ sprint(str, "MSP");
+ break;
+
+ case D_ISP:
+ sprint(str, "ISP");
+ break;
+
+ case D_FPCR:
+ sprint(str, "FPCR");
+ break;
+
+ case D_FPSR:
+ sprint(str, "FPSR");
+ break;
+
+ case D_FPIAR:
+ sprint(str, "FPIAR");
+ break;
+
+ case D_TREE:
+ sprint(str, "TREE");
+ break;
+
+ case D_TC:
+ sprint(str, "TC");
+ break;
+
+ case D_ITT0:
+ sprint(str, "ITT0");
+ break;
+
+ case D_ITT1:
+ sprint(str, "ITT1");
+ break;
+
+ case D_DTT0:
+ sprint(str, "DTT0");
+ break;
+
+ case D_DTT1:
+ sprint(str, "DTT1");
+ break;
+
+ case D_MMUSR:
+ sprint(str, "MMUSR");
+ break;
+ case D_URP:
+ sprint(str, "URP");
+ break;
+
+ case D_SRP:
+ sprint(str, "SRP");
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/sys/src/cmd/1l/mkfile b/sys/src/cmd/1l/mkfile
new file mode 100755
index 000000000..c56fcb5e6
--- /dev/null
+++ b/sys/src/cmd/1l/mkfile
@@ -0,0 +1,22 @@
+</$objtype/mkfile
+
+TARG=1l
+OFILES=\
+ asm.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ list.$O\
+ enam.$O\
+ compat.$O\
+
+HFILES=\
+ l.h\
+ ../2c/2.out.h\
+
+BIN=/$objtype/bin
+</sys/src/cmd/mkone
+
+enam.$O: ../2c/enam.c
+ $CC $CFLAGS ../2c/enam.c
diff --git a/sys/src/cmd/1l/obj.c b/sys/src/cmd/1l/obj.c
new file mode 100755
index 000000000..0622ba37a
--- /dev/null
+++ b/sys/src/cmd/1l/obj.c
@@ -0,0 +1,1413 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char symname[] = SYMDEF;
+char thechar = '1';
+char *thestring = "68000";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is garbage unix
+ * -H1 -T0x80020000 -R4 is garbage format
+ * -H2 -T8224 -R8192 is plan9 format
+ * -H3 -Tx -Rx is next boot
+ * -H4 -T0 -D0 is pilot relocatable
+ */
+
+void
+main(int argc, char *argv[])
+{
+ int i, c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = "1.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0) {
+ diag("usage: 1l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 2;
+ if(debug['B'])
+ HEADTYPE = 2;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ if(INITDAT != -1 && INITRND == -1)
+ INITRND = 0;
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option %ld", HEADTYPE);
+ errorexit();
+
+ case 0: /* this is garbage */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* plan9 boot data goes into text */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 8224;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 8224;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192;
+ break;
+ case 3: /* next boot */
+ HEADR = 28+124+192+24;
+ if(INITTEXT == -1)
+ INITTEXT = 0x04002000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192L;
+ break;
+ case 4: /* preprocess pilot */
+ HEADR = 36L;
+ if(INITTEXT == -1)
+ INITTEXT = 0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
+ }
+
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.to = zprg.from;
+
+ memset(special, 0, sizeof(special));
+ special[D_CCR] = 1;
+ special[D_SR] = 1;
+ special[D_SFC] = 1;
+ special[D_CACR] = 1;
+ special[D_USP] = 1;
+ special[D_VBR] = 1;
+ special[D_CAAR] = 1;
+ special[D_MSP] = 1;
+ special[D_ISP] = 1;
+ special[D_DFC] = 1;
+ special[D_FPCR] = 1;
+ special[D_FPSR] = 1;
+ special[D_FPIAR] = 1;
+ special[D_TC] = 1;
+ special[D_ITT0] = 1;
+ special[D_ITT1] = 1;
+ special[D_DTT0] = 1;
+ special[D_DTT1] = 1;
+ special[D_MMUSR] = 1;
+ special[D_URP] = 1;
+ special[D_SRP] = 1;
+ memset(simple, 0177, sizeof(simple));
+ for(i=0; i<8; i++) {
+ simple[D_R0+i] = i;
+ simple[D_F0+i] = i+0100;
+ simple[D_A0+i] = i+010;
+ simple[D_A0+I_INDIR+i] = i+020;
+ simple[D_A0+I_INDINC+i] = i+030;
+ simple[D_A0+I_INDDEC+i] = i+040;
+ }
+ nuxiinit();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s", outfile);
+ errorexit();
+ }
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ initmuldiv1();
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ errorexit();
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ initmuldiv2();
+ follow();
+ dodata();
+ dostkoff();
+ span();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld data statements\n", ndata);
+ Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ sprint(name, "/%s/lib/lib", thestring);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int c, t, i;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ t = p[0];
+
+ /*
+ * first try the high-time formats
+ */
+ if(t == 0) {
+ a->type = p[1];
+ return 2;
+ }
+ if(t == T_OFFSET) {
+ a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
+ a->type = p[5];
+ return 6;
+ }
+ if(t == (T_OFFSET|T_SYM)) {
+ a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
+ s = h[p[5]];
+ a->sym = s;
+ a->type = p[6];
+ c = 7;
+ goto dosym;
+ }
+ if(t == T_SYM) {
+ s = h[p[1]];
+ a->sym = s;
+ a->type = p[2];
+ c = 3;
+ goto dosym;
+ }
+ if(t == (T_INDEX|T_OFFSET|T_SYM)) {
+ a->displace = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
+ a->offset = p[8] | (p[9]<<8) | (p[10]<<16) | (p[11]<<24);
+ s = h[p[12]];
+ a->sym = s;
+ a->type = p[13];
+ c = 14;
+ goto dosym;
+ }
+
+ /*
+ * now do it the hard way
+ */
+ c = 1;
+ if(t & T_FIELD) {
+ a->field = p[c] | (p[c+1]<<8);
+ c += 2;
+ }
+ if(t & T_INDEX) {
+ a->displace = p[c+3] | (p[c+4]<<8) | (p[c+5]<<16) | (p[c+6]<<24);
+ c += 7;
+ }
+ if(t & T_OFFSET) {
+ a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ c += 4;
+ }
+ if(t & T_SYM) {
+ a->sym = h[p[c]];
+ c += 1;
+ }
+ if(t & T_FCONST) {
+ a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
+ c += 8;
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ for(i=0; i<NSNAME; i++)
+ a->scon[i] = p[c+i];
+ c += NSNAME;
+ a->type = D_SCONST;
+ } else
+ if(t & T_TYPE) {
+ a->type = p[c] | (p[c+1]<<8);
+ c += 2;
+ } else {
+ a->type = p[c];
+ c++;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+
+dosym:
+ t = a->type & D_MASK;
+ if(t != D_AUTO && t != D_PARAM)
+ return c;
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ Prog *p;
+ Sym *h[NSYM], *s;
+ int v, o, r;
+ long ipc, lv;
+ double dv;
+ uchar *bloc, *bsize, *stop;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0] | (bloc[1] << 8);
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .%c file\n", thechar);
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[2]; /* type */
+ o = bloc[3]; /* sym */
+ bloc += 4;
+ c -= 4;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+ p->back = 2;
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ goto loop;
+
+ case ADATA:
+ p->link = datap;
+ datap = p;
+ ndata++;
+ goto loop;
+
+ case AGOK:
+ diag("%s: unknown opcode in %s", pn, TNAME);
+ pc++;
+ goto loop;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ curtext = p;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ s = p->from.sym;
+ if(s->type != 0 && s->type != SXREF)
+ diag("%s: redefinition: %s", pn, s->name);
+ s->type = STEXT;
+ s->value = p->pc;
+ pc++;
+ p->pcond = P;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->pcond = p;
+ etextp = p;
+ goto loop;
+
+ case AJSR:
+ p->as = ABSR;
+
+ case ABSR:
+ if(p->to.type != D_EXTERN && p->to.type != D_STATIC)
+ p->as = AJSR;
+ goto casdef;
+
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv >= -128 && lv < 128)
+ if(p->to.type >= D_R0 && p->to.type < D_R0+8) {
+ p->from.type = D_QUICK;
+ goto casdef;
+ }
+
+ if(lv >= -0x7fff && lv <= 0x7fff)
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ if(p->as == AMOVL)
+ p->as = AMOVW;
+ goto casdef;
+
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv < 0) {
+ lv = -lv;
+ p->from.offset = lv;
+ if(p->as == AADDB)
+ p->as = ASUBB;
+ else
+ if(p->as == AADDW)
+ p->as = ASUBW;
+ else
+ if(p->as == AADDL)
+ p->as = ASUBL;
+ }
+ if(lv > 0)
+ if(lv <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv < 0) {
+ lv = -lv;
+ p->from.offset = lv;
+ if(p->as == ASUBB)
+ p->as = AADDB;
+ else
+ if(p->as == ASUBW)
+ p->as = AADDW;
+ else
+ if(p->as == ASUBL)
+ p->as = AADDL;
+ }
+ if(lv > 0)
+ if(lv <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case AROTRB:
+ case AROTRL:
+ case AROTRW:
+ case AROTLB:
+ case AROTLL:
+ case AROTLW:
+
+ case AASLB:
+ case AASLL:
+ case AASLW:
+ case AASRB:
+ case AASRL:
+ case AASRW:
+ case ALSLB:
+ case ALSLL:
+ case ALSLW:
+ case ALSRB:
+ case ALSRL:
+ case ALSRW:
+ if(p->from.type == D_CONST)
+ if(p->from.offset > 0)
+ if(p->from.offset <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case ATSTL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8) {
+ p->as = ACMPW;
+ p->from = p->to;
+ p->to.type = D_CONST;
+ p->to.offset = 0;
+ }
+ goto casdef;
+
+ case ACMPL:
+ if(p->to.type != D_CONST)
+ goto casdef;
+ lv = p->to.offset;
+ if(lv >= -0x7fff && lv <= 0x7fff)
+ if(p->from.type >= D_A0 && p->from.type < D_A0+8)
+ p->as = ACMPW;
+ goto casdef;
+
+ case ACLRL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8) {
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(p->from.type == D_FCONST)
+ if(optab[p->as].fas != AXXX) {
+ dv = ieeedtod(&p->from.ieee);
+ if(dv >= -(1L<<30) && dv <= (1L<<30)) {
+ lv = dv;
+ if(lv == dv) {
+ p->as = optab[p->as].fas;
+ p->from.type = D_CONST;
+ p->from.offset = lv;
+ p->from.displace = 0;
+ }
+ }
+ }
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ goto loop;
+ }
+ /* not reached */
+
+eof:
+ diag("%s: truncated object file in %s", pn, TNAME);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int l, c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ nsymbol++;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+Prog*
+nprg(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->stkoff = p->stkoff;
+ q->link = p->link;
+ p->link = q;
+ return q;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->as = AADDL;
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ q->from.type = D_CONST;
+ q->from.offset = 1;
+ q->to.type = D_EXTERN;
+ q->to.sym = s;
+ q->to.offset = n*4 + 4;
+
+ q = prg();
+ q->as = ADATA;
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.offset = n*4;
+ q->from.displace = 4;
+ q->to.type = D_EXTERN;
+ q->to.sym = p->from.sym;
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->as = ADATA;
+ q->link = datap;
+ datap = q;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.displace = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *q2, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ if(debug['e']){
+ s2 = lookup("_tracein", 0);
+ s4 = lookup("_traceout", 0);
+ }else{
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ }
+ if(s2->type != STEXT || s4->type != STEXT) {
+ if(debug['e'])
+ diag("_tracein/_traceout not defined %d %d", s2->type, s4->type);
+ else
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->from.displace = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->from.displace = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.displace != 0) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ if(debug['e']){ /* embedded tracing */
+ q2 = prg();
+ p->link = q2;
+ q2->link = q;
+
+ q2->line = p->line;
+ q2->pc = p->pc;
+
+ q2->as = AJMP;
+ q2->to.type = D_BRANCH;
+ q2->to.sym = p->to.sym;
+ q2->pcond = q->link;
+ }else
+ p->link = q;
+ p = q;
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARTS) {
+ /*
+ * RTS (default)
+ */
+ if(debug['e']){ /* embedded tracing */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ }
+ /*
+ * RTS
+ */
+ q = prg();
+ q->as = ARTS;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BSR profout
+ */
+ p->as = ABSR;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+long
+reuse(Prog *r, Sym *s)
+{
+ Prog *p;
+
+
+ if(r == P)
+ return 0;
+ for(p = datap; p != r; p = p->link)
+ if(p->to.sym == s)
+ return p->from.offset;
+ return 0;
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x01020304L, i+1);
+ if(i >= 2)
+ inuxi2[i-2] = c;
+ if(i >= 3)
+ inuxi1[i-3] = c;
+ inuxi4[i] = c;
+ fnuxi8[i] = c+4;
+ fnuxi8[i+4] = c;
+ c = find2(0x01020304L, i+1);
+ gnuxi8[i] = c+4;
+ gnuxi8[i+4] = c;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\n[fg]nuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", gnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+int
+find2(long l, int c)
+{
+ short *p;
+ int i;
+
+ p = (short*)&l;
+ for(i=0; i<4; i+=2) {
+ if(((*p >> 8) & 0xff) == c)
+ return i;
+ if((*p++ & 0xff) == c)
+ return i+1;
+ }
+ return 0;
+}
+
+long
+ieeedtof(Ieee *e)
+{
+ int exp;
+ long v;
+
+ if(e->h == 0)
+ return 0;
+ exp = (e->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (e->h & 0xfffffL) << 3;
+ v |= (e->l >> 29) & 0x7L;
+ if((e->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= e->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
diff --git a/sys/src/cmd/1l/optab.c b/sys/src/cmd/1l/optab.c
new file mode 100755
index 000000000..2109b478a
--- /dev/null
+++ b/sys/src/cmd/1l/optab.c
@@ -0,0 +1,444 @@
+#include "l.h"
+
+#define X1 0
+#define X2 0
+#define X3 0
+#define C 0xf200
+
+Optab optab[] =
+/* as, fas, srcsp, dstsp, optype, opcode */
+{
+ { AXXX },
+ { AABCD, AXXX, X1, X2, X3, 0x4e71 },
+ { AADDB, AXXX, 2, 0, 3, 0xd000, 0x5000, 0, 0x0600 },
+ { AADDL, AXXX, 4, 0, 3, 0xd080, 0x5080, 0xd1c0, 0x0680 },
+ { AADDW, AXXX, 2, 0, 3, 0xd040, 0x5040, 0xd0c0, 0x0640 },
+ { AADDXB },
+ { AADDXL },
+ { AADDXW },
+ { AADJSP },
+ { AANDB, AXXX, 2, 0, 9, 0xc000, 0xc100, 0x0200 },
+ { AANDL, AXXX, 4, 0, 9, 0xc080, 0xc180, 0x0280 },
+ { AANDW, AXXX, 2, 0, 9, 0xc040, 0xc140, 0x0240 },
+ { AASLB, AXXX, 0, 2, 12, 0xe100 },
+ { AASLL, AXXX, 0, 4, 12, 0xe180 },
+ { AASLW, AXXX, 0, 2, 12, 0xe140 },
+ { AASRB, AXXX, 0, 2, 12, 0xe000 },
+ { AASRL, AXXX, 0, 4, 12, 0xe080 },
+ { AASRW, AXXX, 0, 2, 12, 0xe040 },
+ { ABCASE },
+ { ABCC, AXXX, 0, 0, 1, 0x6400 },
+ { ABCHG, AXXX, 2, 2, 27, 0x0140, 0x0840 },
+ { ABCLR, AXXX, 2, 2, 27, 0x0180, 0x0880 },
+ { ABCS, AXXX, 0, 0, 1, 0x6500 },
+ { ABEQ, AXXX, 0, 0, 1, 0x6700 },
+ { ABFCHG },
+ { ABFCLR },
+ { ABFEXTS },
+ { ABFEXTU },
+ { ABFFFO },
+ { ABFINS },
+ { ABFSET },
+ { ABFTST },
+ { ABGE, AXXX, 0, 0, 1, 0x6c00 },
+ { ABGT, AXXX, 0, 0, 1, 0x6e00 },
+ { ABHI, AXXX, 0, 0, 1, 0x6200 },
+ { ABKPT },
+ { ABLE, AXXX, 0, 0, 1, 0x6f00 },
+ { ABLS, AXXX, 0, 0, 1, 0x6300 },
+ { ABLT, AXXX, 0, 0, 1, 0x6d00 },
+ { ABMI, AXXX, 0, 0, 1, 0x6b00 },
+ { ABNE, AXXX, 0, 0, 1, 0x6600 },
+ { ABPL, AXXX, 0, 0, 1, 0x6a00 },
+ { ABRA, AXXX, 0, 0, 1, 0x6000, 0x4ec0 },
+ { ABSET, AXXX, 2, 2, 27, 0x01c0, 0x08c0 },
+ { ABSR, AXXX, 0, 0, 1, 0x6100, 0x4e80 },
+ { ABTST, AXXX, 2, 2, 27, 0x0100, 0x0800 },
+ { ABVC, AXXX, 0, 0, 1, 0x6800 },
+ { ABVS, AXXX, 0, 0, 1, 0x6900 },
+ { ACALLM },
+ { ACAS2B },
+ { ACAS2L },
+ { ACAS2W },
+ { ACASB },
+ { ACASEW },
+ { ACASL },
+ { ACASW },
+ { ACHK2B },
+ { ACHK2L },
+ { ACHK2W },
+ { ACHKL, AXXX, 4, 4, 26, 0x4100 },
+ { ACHKW, AXXX, 2, 2, 26, 0x4180 },
+ { ACLRB, AXXX, 0, -2, 5, 0x4200 },
+ { ACLRL, AXXX, 0, -4, 5, 0x4280 },
+ { ACLRW, AXXX, 0, -2, 5, 0x4240 },
+ { ACMP2B },
+ { ACMP2L },
+ { ACMP2W },
+ { ACMPB, AXXX, 2, 2, 7, 0xb000, 0, 0x0c00, 0xb108 },
+ { ACMPL, AXXX, 4, 4, 7, 0xb080, 0xb100, 0x0c80, 0xb188 },
+ { ACMPW, AXXX, 2, 2, 7, 0xb040, 0xb080, 0x0c40, 0xb148 },
+ { ADATA },
+ { ADBCC, AXXX, 0, 0, 15, 0x54c8 },
+ { ADBCS, AXXX, 0, 0, 15, 0x55c8 },
+ { ADBEQ, AXXX, 0, 0, 15, 0x57c8 },
+ { ADBF, AXXX, 0, 0, 15, 0x51c8 },
+ { ADBGE, AXXX, 0, 0, 15, 0x5cc8 },
+ { ADBGT, AXXX, 0, 0, 15, 0x5ec8 },
+ { ADBHI, AXXX, 0, 0, 15, 0x52c8 },
+ { ADBLE, AXXX, 0, 0, 15, 0x5fc8 },
+ { ADBLS, AXXX, 0, 0, 15, 0x53c8 },
+ { ADBLT, AXXX, 0, 0, 15, 0x5dc8 },
+ { ADBMI, AXXX, 0, 0, 15, 0x5bc8 },
+ { ADBNE, AXXX, 0, 0, 15, 0x56c8 },
+ { ADBPL, AXXX, 0, 0, 15, 0x5ac8 },
+ { ADBT, AXXX, 0, 0, 15, 0x50c8 },
+ { ADBVC, AXXX, 0, 0, 15, 0x58c8 },
+ { ADBVS, AXXX, 0, 0, 15, 0x59c8 },
+ { ADIVSL, AXXX, 4, 0, 14, 0x4c40, 0x0800 },
+ { ADIVSW, AXXX, 2, 0, 13, 0x81c0 },
+ { ADIVUL, AXXX, 4, 0, 14, 0x4c40, 0x0000 },
+ { ADIVUW, AXXX, 2, 0, 13, 0x80c0 },
+ { AEND },
+ { AEORB, AXXX, 2, 0, 10, 0xb100, 0x0a00 },
+ { AEORL, AXXX, 4, 0, 10, 0xb180, 0x0a80 },
+ { AEORW, AXXX, 2, 0, 10, 0xb140, 0x0a40 },
+ { AEXG },
+ { AEXTBL },
+ { AEXTBW, AXXX, 0, 0, 11, 0x4880 },
+ { AEXTWL, AXXX, 0, 0, 11, 0x48c0 },
+ { AFABSB, AXXX, 2, 0, 17, C, 0x0018, 0x5818 },
+ { AFABSD, AFABSL, 8, 0, 17, C, 0x0018, 0x5418 },
+ { AFABSF, AFABSL, 4, 0, 17, C, 0x0018, 0x4418 },
+ { AFABSL, AXXX, 4, 0, 17, C, 0x0018, 0x4018 },
+ { AFABSW, AXXX, 2, 0, 17, C, 0x0018, 0x5018 },
+ { AFACOSB, AXXX, 2, 0, 17, C, 0x001c, 0x581c },
+ { AFACOSD, AFACOSL, 8, 0, 17, C, 0x001c, 0x541c },
+ { AFACOSF, AFACOSL, 4, 0, 17, C, 0x001c, 0x441c },
+ { AFACOSL, AXXX, 4, 0, 17, C, 0x001c, 0x401c },
+ { AFACOSW, AXXX, 2, 0, 17, C, 0x001c, 0x501c },
+ { AFADDB, AXXX, 2, 0, 17, C, 0x0022, 0x5822 },
+ { AFADDD, AFADDL, 8, 0, 17, C, 0x0022, 0x5422 },
+ { AFADDF, AFADDL, 4, 0, 17, C, 0x0022, 0x4422 },
+ { AFADDL, AXXX, 4, 0, 17, C, 0x0022, 0x4022 },
+ { AFADDW, AXXX, 2, 0, 17, C, 0x0022, 0x5022 },
+ { AFASINB, AXXX, 2, 0, 17, C, 0x000c, 0x580c },
+ { AFASIND, AFASINL, 8, 0, 17, C, 0x000c, 0x540c },
+ { AFASINF, AFASINL, 4, 0, 17, C, 0x000c, 0x440c },
+ { AFASINL, AXXX, 4, 0, 17, C, 0x000c, 0x400c },
+ { AFASINW, AXXX, 2, 0, 17, C, 0x000c, 0x500c },
+ { AFATANB, AXXX, 2, 0, 17, C, 0x000a, 0x580a },
+ { AFATAND, AFATANL, 8, 0, 17, C, 0x000a, 0x540a },
+ { AFATANF, AFATANL, 4, 0, 17, C, 0x000a, 0x440a },
+ { AFATANHB, AXXX, 2, 0, 17, C, 0x000d, 0x580d },
+ { AFATANHD, AFATANHL, 8, 0, 17, C, 0x000d, 0x540d },
+ { AFATANHF, AFATANHL, 4, 0, 17, C, 0x000d, 0x440d },
+ { AFATANHL, AXXX, 4, 0, 17, C, 0x000d, 0x400d },
+ { AFATANHW, AXXX, 2, 0, 17, C, 0x000d, 0x500d },
+ { AFATANL, AXXX, 4, 0, 17, C, 0x000a, 0x400a },
+ { AFATANW, AXXX, 2, 0, 17, C, 0x000a, 0x500a },
+ { AFBEQ, AXXX, 0, 0, 18, C+0x81 },
+ { AFBF, AXXX, 0, 0, 18, C+0x8f },
+ { AFBGE, AXXX, 0, 0, 18, C+0x93 },
+ { AFBGT, AXXX, 0, 0, 18, C+0x92 },
+ { AFBLE, AXXX, 0, 0, 18, C+0x95 },
+ { AFBLT, AXXX, 0, 0, 18, C+0x94 },
+ { AFBNE, AXXX, 0, 0, 18, C+0x8e },
+ { AFBT, AXXX, 0, 0, 18, C+0x80 },
+ { AFCMPB, AXXX, 0, 2, 22, C, 0x0038, 0x5838 },
+ { AFCMPD, AFCMPL, 0, 8, 22, C, 0x0038, 0x5438 },
+ { AFCMPF, AFCMPL, 0, 4, 22, C, 0x0038, 0x4438 },
+ { AFCMPL, AXXX, 0, 4, 22, C, 0x0038, 0x4038 },
+ { AFCMPW, AXXX, 0, 2, 22, C, 0x0038, 0x5038 },
+ { AFCOSB, AXXX, 2, 0, 17, C, 0x001d, 0x581d },
+ { AFCOSD, AFCOSL, 8, 0, 17, C, 0x001d, 0x541d },
+ { AFCOSF, AFCOSL, 4, 0, 17, C, 0x001d, 0x441d },
+ { AFCOSHB, AXXX, 2, 0, 17, C, 0x0019, 0x5819 },
+ { AFCOSHD, AFCOSHL, 8, 0, 17, C, 0x0019, 0x5419 },
+ { AFCOSHF, AFCOSHL, 4, 0, 17, C, 0x0019, 0x4419 },
+ { AFCOSHL, AXXX, 4, 0, 17, C, 0x0019, 0x4019 },
+ { AFCOSHW, AXXX, 2, 0, 17, C, 0x0019, 0x5019 },
+ { AFCOSL, AXXX, 4, 0, 17, C, 0x001d, 0x401d },
+ { AFCOSW, AXXX, 2, 0, 17, C, 0x001d, 0x501d },
+ { AFDBEQ, AXXX, 0, 0, 19, C+0x48, 0x01 },
+ { AFDBF, AXXX, 0, 0, 19, C+0x48, 0x0f },
+ { AFDBGE, AXXX, 0, 0, 19, C+0x48, 0x13 },
+ { AFDBGT, AXXX, 0, 0, 19, C+0x48, 0x12 },
+ { AFDBLE, AXXX, 0, 0, 19, C+0x48, 0x15 },
+ { AFDBLT, AXXX, 0, 0, 19, C+0x48, 0x14 },
+ { AFDBNE, AXXX, 0, 0, 19, C+0x48, 0x0e },
+ { AFDBT, AXXX, 0, 0, 19, C+0x48, 0x00 },
+ { AFDIVB, AXXX, 2, 0, 17, C, 0x0020, 0x5820 },
+ { AFDIVD, AFDIVL, 8, 0, 17, C, 0x0020, 0x5420 },
+ { AFDIVF, AFDIVL, 4, 0, 17, C, 0x0020, 0x4420 },
+ { AFDIVL, AXXX, 4, 0, 17, C, 0x0020, 0x4020 },
+ { AFDIVW, AXXX, 2, 0, 17, C, 0x0020, 0x5020 },
+ { AFETOXB, AXXX, 2, 0, 17, C, 0x0010, 0x5810 },
+ { AFETOXD, AFETOXL, 8, 0, 17, C, 0x0010, 0x5410 },
+ { AFETOXF, AFETOXL, 4, 0, 17, C, 0x0010, 0x4410 },
+ { AFETOXL, AXXX, 4, 0, 17, C, 0x0010, 0x4010 },
+ { AFETOXM1B, AXXX, 2, 0, 17, C, 0x0008, 0x5808 },
+ { AFETOXM1D, AFETOXM1L, 8, 0, 17, C, 0x0008, 0x5408 },
+ { AFETOXM1F, AFETOXM1L, 4, 0, 17, C, 0x0008, 0x4408 },
+ { AFETOXM1L, AXXX, 4, 0, 17, C, 0x0008, 0x4008 },
+ { AFETOXM1W, AXXX, 2, 0, 17, C, 0x0008, 0x5008 },
+ { AFETOXW, AXXX, 2, 0, 17, C, 0x0010, 0x5010 },
+ { AFGETEXPB, AXXX, 2, 0, 17, C, 0x001e, 0x581e },
+ { AFGETEXPD, AFGETEXPL, 8, 0, 17, C, 0x001e, 0x541e },
+ { AFGETEXPF, AFGETEXPL, 4, 0, 17, C, 0x001e, 0x441e },
+ { AFGETEXPL, AXXX, 4, 0, 17, C, 0x001e, 0x401e },
+ { AFGETEXPW, AXXX, 2, 0, 17, C, 0x001e, 0x501e },
+ { AFGETMANB, AXXX, 2, 0, 17, C, 0x001f, 0x581f },
+ { AFGETMAND, AFGETMANL, 8, 0, 17, C, 0x001f, 0x541f },
+ { AFGETMANF, AFGETMANL, 4, 0, 17, C, 0x001f, 0x441f },
+ { AFGETMANL, AXXX, 4, 0, 17, C, 0x001f, 0x401f },
+ { AFGETMANW, AXXX, 2, 0, 17, C, 0x001f, 0x501f },
+ { AFINTB, AXXX, 2, 0, 17, C, 0x0001, 0x5801 },
+ { AFINTD, AFINTL, 8, 0, 17, C, 0x0001, 0x5401 },
+ { AFINTF, AFINTL, 4, 0, 17, C, 0x0001, 0x4401 },
+ { AFINTL, AXXX, 4, 0, 17, C, 0x0001, 0x4001 },
+ { AFINTRZB, AXXX, 2, 0, 17, C, 0x0003, 0x5803 },
+ { AFINTRZD, AFINTRZL, 8, 0, 17, C, 0x0003, 0x5403 },
+ { AFINTRZF, AFINTRZL, 4, 0, 17, C, 0x0003, 0x4403 },
+ { AFINTRZL, AXXX, 4, 0, 17, C, 0x0003, 0x4003 },
+ { AFINTRZW, AXXX, 2, 0, 17, C, 0x0003, 0x5003 },
+ { AFINTW, AXXX, 2, 0, 17, C, 0x0001, 0x5001 },
+ { AFLOG10B, AXXX, 2, 0, 17, C, 0x0015, 0x5815 },
+ { AFLOG10D, AFLOG10L, 8, 0, 17, C, 0x0015, 0x5415 },
+ { AFLOG10F, AFLOG10L, 4, 0, 17, C, 0x0015, 0x4415 },
+ { AFLOG10L, AXXX, 4, 0, 17, C, 0x0015, 0x4015 },
+ { AFLOG10W, AXXX, 2, 0, 17, C, 0x0015, 0x5015 },
+ { AFLOG2B, AXXX, 2, 0, 17, C, 0x0016, 0x5816 },
+ { AFLOG2D, AFLOG2L, 8, 0, 17, C, 0x0016, 0x5416 },
+ { AFLOG2F, AFLOG2L, 4, 0, 17, C, 0x0016, 0x4416 },
+ { AFLOG2L, AXXX, 4, 0, 17, C, 0x0016, 0x4016 },
+ { AFLOG2W, AXXX, 2, 0, 17, C, 0x0016, 0x5016 },
+ { AFLOGNB, AXXX, 2, 0, 17, C, 0x0014, 0x5814 },
+ { AFLOGND, AFLOGNL, 8, 0, 17, C, 0x0014, 0x5414 },
+ { AFLOGNF, AFLOGNL, 4, 0, 17, C, 0x0014, 0x4414 },
+ { AFLOGNL, AXXX, 4, 0, 17, C, 0x0014, 0x4014 },
+ { AFLOGNP1B, AXXX, 2, 0, 17, C, 0x0006, 0x5806 },
+ { AFLOGNP1D, AFLOGNP1L, 8, 0, 17, C, 0x0006, 0x5406 },
+ { AFLOGNP1F, AFLOGNP1L, 4, 0, 17, C, 0x0006, 0x4406 },
+ { AFLOGNP1L, AXXX, 4, 0, 17, C, 0x0006, 0x4006 },
+ { AFLOGNP1W, AXXX, 2, 0, 17, C, 0x0006, 0x5006 },
+ { AFLOGNW, AXXX, 2, 0, 17, C, 0x0014, 0x5014 },
+ { AFMODB, AXXX, 2, 0, 17, C, 0x0021, 0x5821 },
+ { AFMODD, AFMODL, 8, 0, 17, C, 0x0021, 0x5421 },
+ { AFMODF, AFMODL, 4, 0, 17, C, 0x0021, 0x4421 },
+ { AFMODL, AXXX, 4, 0, 17, C, 0x0021, 0x4021 },
+ { AFMODW, AXXX, 2, 0, 17, C, 0x0021, 0x5021 },
+ { AFMOVEB, AXXX, 2, -2, 16, C, 0x0000, 0x7800, 0x5800 },
+ { AFMOVED, AFMOVEL, 8, -8, 16, C, 0x0000, 0x7400, 0x5400 },
+ { AFMOVEF, AFMOVEL, 4, -4, 16, C, 0x0000, 0x6400, 0x4400 },
+ { AFMOVEL, AXXX, 4, -4, 16, C, 0x0000, 0x6000, 0x4000 },
+ { AFMOVEM, AXXX, 2, 2, 28, C },
+ { AFMOVEMC, AXXX, 2, 2, 29, C },
+ { AFMOVEW, AXXX, 2, -2, 16, C, 0x0000, 0x7000, 0x5000 },
+ { AFMULB, AXXX, 2, 0, 17, C, 0x0023, 0x5823 },
+ { AFMULD, AFMULL, 8, 0, 17, C, 0x0023, 0x5423 },
+ { AFMULF, AFMULL, 4, 0, 17, C, 0x0023, 0x4423 },
+ { AFMULL, AXXX, 4, 0, 17, C, 0x0023, 0x4023 },
+ { AFMULW, AXXX, 2, 0, 17, C, 0x0023, 0x5023 },
+ { AFNEGB, AXXX, 2, 0, 21, C, 0x001a, 0x581a },
+ { AFNEGD, AFNEGL, 8, 0, 21, C, 0x001a, 0x541a },
+ { AFNEGF, AFNEGL, 4, 0, 21, C, 0x001a, 0x441a },
+ { AFNEGL, AXXX, 4, 0, 21, C, 0x001a, 0x401a },
+ { AFNEGW, AXXX, 2, 0, 21, C, 0x001a, 0x501a },
+ { AFREMB, AXXX, 2, 0, 17, C, 0x0025, 0x5825 },
+ { AFREMD, AFREML, 8, 0, 17, C, 0x0025, 0x5425 },
+ { AFREMF, AFREML, 4, 0, 17, C, 0x0025, 0x4425 },
+ { AFREML, AXXX, 4, 0, 17, C, 0x0025, 0x4025 },
+ { AFREMW, AXXX, 2, 0, 17, C, 0x0025, 0x5025 },
+ { AFRESTORE, AXXX, 0, 2, 5, C+0x0140 },
+ { AFSAVE, AXXX, 0, 2, 5, C+0x0100 },
+ { AFSCALEB, AXXX, 2, 0, 17, C, 0x0026, 0x5826 },
+ { AFSCALED, AFSCALEL, 8, 0, 17, C, 0x0026, 0x5426 },
+ { AFSCALEF, AFSCALEL, 4, 0, 17, C, 0x0026, 0x4426 },
+ { AFSCALEL, AXXX, 4, 0, 17, C, 0x0026, 0x4026 },
+ { AFSCALEW, AXXX, 2, 0, 17, C, 0x0026, 0x5026 },
+ { AFSEQ, AXXX, X1, X2, X3, 0xffff },
+ { AFSF, AXXX, 4, X2, X3, 0xffff },
+ { AFSGE, AXXX, X1, X2, X3, 0xffff },
+ { AFSGT, AXXX, X1, X2, X3, 0xffff },
+ { AFSINB, AXXX, 2, 0, 17, C, 0x000e, 0x580e },
+ { AFSIND, AFSINL, 8, 0, 17, C, 0x000e, 0x540e },
+ { AFSINF, AFSINL, 4, 0, 17, C, 0x000e, 0x440e },
+ { AFSINHB, AXXX, 2, 0, 17, C, 0x0002, 0x5802 },
+ { AFSINHD, AFSINHL, 8, 0, 17, C, 0x0002, 0x5402 },
+ { AFSINHF, AFSINHL, 4, 0, 17, C, 0x0002, 0x4402 },
+ { AFSINHL, AXXX, 4, 0, 17, C, 0x0002, 0x4002 },
+ { AFSINHW, AXXX, 2, 0, 17, C, 0x0002, 0x5002 },
+ { AFSINL, AXXX, 4, 0, 17, C, 0x000e, 0x400e },
+ { AFSINW, AXXX, 2, 0, 17, C, 0x000e, 0x500e },
+ { AFSLE, AXXX, X1, X2, X3, 0xffff },
+ { AFSLT, AXXX, X1, X2, X3, 0xffff },
+ { AFSNE, AXXX, X1, X2, X3, 0xffff },
+ { AFSQRTB, AXXX, 2, 0, 17, C, 0x0004, 0x5804 },
+ { AFSQRTD, AFSQRTL, 8, 0, 17, C, 0x0004, 0x5404 },
+ { AFSQRTF, AFSQRTL, 4, 0, 17, C, 0x0004, 0x4404 },
+ { AFSQRTL, AXXX, 4, 0, 17, C, 0x0004, 0x4004 },
+ { AFSQRTW, AXXX, 2, 0, 17, C, 0x0004, 0x5004 },
+ { AFST, AXXX, X1, X2, X3, 0xffff },
+ { AFSUBB, AXXX, 2, 0, 17, C, 0x0028, 0x5828 },
+ { AFSUBD, AFSUBL, 8, 0, 17, C, 0x0028, 0x5428 },
+ { AFSUBF, AFSUBL, 4, 0, 17, C, 0x0028, 0x4428 },
+ { AFSUBL, AXXX, 4, 0, 17, C, 0x0028, 0x4028 },
+ { AFSUBW, AXXX, 2, 0, 17, C, 0x0028, 0x5028 },
+ { AFTANB, AXXX, 2, 0, 17, C, 0x000f, 0x580f },
+ { AFTAND, AFTANL, 8, 0, 17, C, 0x000f, 0x540f },
+ { AFTANF, AFTANL, 4, 0, 17, C, 0x000f, 0x440f },
+ { AFTANHB, AXXX, 2, 0, 17, C, 0x0009, 0x5809 },
+ { AFTANHD, AFTANHL, 8, 0, 17, C, 0x0009, 0x5409 },
+ { AFTANHF, AFTANHL, 4, 0, 17, C, 0x0009, 0x4409 },
+ { AFTANHL, AXXX, 4, 0, 17, C, 0x0009, 0x4009 },
+ { AFTANHW, AXXX, 2, 0, 17, C, 0x0009, 0x5009 },
+ { AFTANL, AXXX, 4, 0, 17, C, 0x000f, 0x400f },
+ { AFTANW, AXXX, 2, 0, 17, C, 0x000f, 0x500f },
+ { AFTENTOXB, AXXX, 2, 0, 17, C, 0x0012, 0x5812 },
+ { AFTENTOXD, AFTENTOXL, 8, 0, 17, C, 0x0012, 0x5412 },
+ { AFTENTOXF, AFTENTOXL, 4, 0, 17, C, 0x0012, 0x4412 },
+ { AFTENTOXL, AXXX, 4, 0, 17, C, 0x0012, 0x4012 },
+ { AFTENTOXW, AXXX, 2, 0, 17, C, 0x0012, 0x5012 },
+ { AFTSTB, AXXX, 0, 2, 20, C, 0x003a, 0x583a },
+ { AFTSTD, AFTSTL, 0, 8, 20, C, 0x003a, 0x543a },
+ { AFTSTF, AFTSTL, 0, 4, 20, C, 0x003a, 0x443a },
+ { AFTSTL, AXXX, 0, 4, 20, C, 0x003a, 0x403a },
+ { AFTSTW, AXXX, 0, 2, 20, C, 0x003a, 0x503a },
+ { AFTWOTOXB, AXXX, 2, 0, 17, C, 0x0011, 0x5811 },
+ { AFTWOTOXD, AFTWOTOXL, 8, 0, 17, C, 0x0011, 0x5411 },
+ { AFTWOTOXF, AFTWOTOXL, 4, 0, 17, C, 0x0011, 0x4411 },
+ { AFTWOTOXL, AXXX, 4, 0, 17, C, 0x0011, 0x4011 },
+ { AFTWOTOXW, AXXX, 2, 0, 17, C, 0x0011, 0x5011 },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AILLEG, AXXX, 0, 0, 4, 0x4efc },
+ { AINSTR },
+ { AJMP, AXXX, 0, 0, 5, 0x4ec0 },
+ { AJSR, AXXX, 0, 0, 5, 0x4e80 },
+ { ALEA, AXXX, 0, 0, 6, 0x41c0 },
+ { ALINKL },
+ { ALINKW },
+ { ALOCATE },
+ { ALONG, AXXX, 0, 4, 23 },
+ { ALSLB, AXXX, 0, 2, 12, 0xe108 },
+ { ALSLL, AXXX, 0, 4, 12, 0xe188 },
+ { ALSLW, AXXX, 0, 2, 12, 0xe148 },
+ { ALSRB, AXXX, 0, 2, 12, 0xe008 },
+ { ALSRL, AXXX, 0, 4, 12, 0xe088 },
+ { ALSRW, AXXX, 0, 2, 12, 0xe048 },
+ { AMOVB, AXXX, 2, -2, 2, 0x1000, 0x7000 },
+ { AMOVEM, AXXX, 2, 2, 25, 0x48c0 },
+ { AMOVEPL },
+ { AMOVEPW },
+ { AMOVESB },
+ { AMOVESL },
+ { AMOVESW, },
+ { AMOVL, AXXX, 4, -4, 2, 0x2000, 0x7000 },
+ { AMOVW, AXXX, 2, -2, 2, 0x3000, 0x7000 },
+ { AMULSL, AXXX, 4, 0, 14, 0x4c00, 0x0800 },
+ { AMULSW, AXXX, 2, 0, 13, 0xc1c0 },
+ { AMULUL, AXXX, 4, 0, 14, 0x4c00, 0x0000 },
+ { AMULUW, AXXX, 2, 0, 13, 0xc0c0 },
+ { ANAME },
+ { ANBCD },
+ { ANEGB, AXXX, 0, 0, 5, 0x4400 },
+ { ANEGL, AXXX, 0, 0, 5, 0x4480 },
+ { ANEGW, AXXX, 0, 0, 5, 0x4440 },
+ { ANEGXB },
+ { ANEGXL },
+ { ANEGXW },
+ { ANOP },
+ { ANOTB, AXXX, 0, 0, 5, 0x4600 },
+ { ANOTL, AXXX, 0, 0, 5, 0x4680 },
+ { ANOTW, AXXX, 0, 0, 5, 0x4640 },
+ { AORB, AXXX, 2, 0, 9, 0x8000, 0x8100, 0x0000 },
+ { AORL, AXXX, 4, 0, 9, 0x8080, 0x8180, 0x0080 },
+ { AORW, AXXX, 2, 0, 9, 0x8040, 0x8140, 0x0040 },
+ { APACK },
+ { APEA, AXXX, 0, 0, 5, 0x4840 },
+ { ARESET },
+ { AROTLB, AXXX, 0, 2, 12, 0xe118 },
+ { AROTLL, AXXX, 0, 4, 12, 0xe198 },
+ { AROTLW, AXXX, 0, 2, 12, 0xe158 },
+ { AROTRB, AXXX, 0, 2, 12, 0xe018 },
+ { AROTRL, AXXX, 0, 4, 12, 0xe098 },
+ { AROTRW, AXXX, 0, 2, 12, 0xe058 },
+ { AROXLB },
+ { AROXLL },
+ { AROXLW },
+ { AROXRB },
+ { AROXRL },
+ { AROXRW },
+ { ARTD },
+ { ARTE, AXXX, 0, 0, 4, 0x4e73 },
+ { ARTM },
+ { ARTR },
+ { ARTS, AXXX, 0, 0, 4, 0x4e75 },
+ { ASBCD },
+ { ASCC },
+ { ASCS },
+ { ASEQ },
+ { ASF },
+ { ASGE },
+ { ASGT },
+ { ASHI },
+ { ASLE },
+ { ASLS },
+ { ASLT },
+ { ASMI },
+ { ASNE },
+ { ASPL },
+ { AST },
+ { ASTOP },
+ { ASUBB, AXXX, 2, 0, 3, 0x9000, 0x5100, 0, 0x0400 },
+ { ASUBL, AXXX, 4, 0, 3, 0x9080, 0x5180, 0x91c0, 0x0480 },
+ { ASUBW, AXXX, 2, 0, 3, 0x9040, 0x5140, 0x90c0, 0x0440 },
+ { ASUBXB },
+ { ASUBXL },
+ { ASUBXW },
+ { ASVC },
+ { ASVS },
+ { ASWAP, AXXX, 0, 0, 35, 0x4840 },
+ { ASYS, AXXX, 0, 2, 8, 0x4e40 },
+ { ATAS, AXXX, 0, 2, 5, 0x4ac0 },
+ { ATEXT },
+ { ATRAP, AXXX, 0, 0, 30, 0x4e40 },
+ { ATRAPCC },
+ { ATRAPCS },
+ { ATRAPEQ },
+ { ATRAPF },
+ { ATRAPGE },
+ { ATRAPGT },
+ { ATRAPHI },
+ { ATRAPLE },
+ { ATRAPLS },
+ { ATRAPLT },
+ { ATRAPMI },
+ { ATRAPNE },
+ { ATRAPPL },
+ { ATRAPT },
+ { ATRAPV },
+ { ATRAPVC },
+ { ATRAPVS },
+ { ATSTB, AXXX, 0, 2, 5, 0x4a00 },
+ { ATSTL, AXXX, 0, 4, 5, 0x4a80 },
+ { ATSTW, AXXX, 0, 2, 5, 0x4a40 },
+ { AUNLK },
+ { AUNPK },
+ { AWORD, AXXX, 0, 2, 23 },
+ { AXXX }
+};
+
+char mmsize[] =
+{
+ /* 0 */ 0, 2, 2, 2, 2,
+ /* 5 */ 2, 2, 2, 4, 2,
+ /* 10 */ 2, 2, 2, 2, 4,
+ /* 15 */ 4, 4, 4, 4, 6,
+ /* 20 */ 4, 4, 4, 0, 4,
+ /* 25 */ 2, 2, 2, 2, 2,
+ /* 30 */ 2, 4, 4, 0, 4,
+ /* 35 */ 2, 0, 0, 0, 0,
+};
diff --git a/sys/src/cmd/1l/pass.c b/sys/src/cmd/1l/pass.c
new file mode 100755
index 000000000..349026b1c
--- /dev/null
+++ b/sys/src/cmd/1l/pass.c
@@ -0,0 +1,673 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i;
+ Sym *s;
+ Prog *p;
+ long t, u;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ t = p->from.offset + p->from.displace;
+ if(t > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ /* allocate small guys */
+ datsize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA)
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t == 0) {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ t = rnd(t, 4);;
+ s->value = t;
+ if(t > MINSIZ)
+ continue;
+ s->value = datsize;
+ datsize += t;
+ s->type = SDATA1;
+ }
+
+ /* allocate the rest of the data */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA) {
+ if(s->type == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ t = s->value;
+ s->value = datsize;
+ datsize += t;
+ }
+
+ if(debug['j']) {
+ /*
+ * pad data with bss that fits up to next
+ * 8k boundary, then push data to 8k
+ */
+ u = rnd(datsize, 8192);
+ u -= datsize;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t > u)
+ continue;
+ u -= t;
+ s->value = datsize;
+ s->type = SDATA;
+ datsize += t;
+ }
+ datsize += u;
+ }
+
+ /* now the bss */
+ bsssize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ s->value = bsssize + datsize;
+ bsssize += t;
+ }
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+}
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != ABRA)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+ Prog *p;
+ long o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+ lastp->link = P;
+ firstp = firstp->link;
+ o = 0; /* set */
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+
+ p->stkoff = -1; /* initialization for stkoff */
+ if(p->as == ATEXT) {
+ p->stkoff = 0;
+ o = p->to.offset;
+ continue;
+ }
+ if(p->as == AADJSP && p->from.offset == 0) {
+ p->stkoff = o;
+ continue;
+ }
+ }
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == ABRA)
+ if((q = p->pcond) != P) {
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /* copy up to 4 instructions to avoid branch */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == P)
+ break;
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == ABRA || a == ARTS || a == ARTE)
+ break;
+ if(q->pcond == P || q->pcond->mark)
+ continue;
+ if(a == ABSR || a == ADBF)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ lastp->link = q;
+ lastp = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = prg();
+ q->as = ABRA;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark = 1;
+ lastp->link = p;
+ lastp = p;
+ a = p->as;
+ if(a == ARTS || a == ABRA || a == ARTE)
+ return;
+ if(p->pcond != P)
+ if(a != ABSR) {
+ q = brchain(p->link);
+ if(q != P && q->mark)
+ if(a != ADBF) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABLE: return ABGT;
+ case ABLS: return ABHI;
+ case ABLT: return ABGE;
+ case ABMI: return ABPL;
+ case ABGE: return ABLT;
+ case ABPL: return ABMI;
+ case ABGT: return ABLE;
+ case ABHI: return ABLS;
+ case ABCS: return ABCC;
+ case ABCC: return ABCS;
+ case AFBEQ: return AFBNE;
+ case AFBF: return AFBT;
+ case AFBGE: return AFBLT;
+ case AFBGT: return AFBLE;
+ case AFBLE: return AFBGT;
+ case AFBLT: return AFBGE;
+ case AFBNE: return AFBEQ;
+ case AFBT: return AFBF;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ return a;
+}
+
+void
+patch(void)
+{
+ long c;
+ Prog *p, *q;
+ Sym *s;
+ long vexit;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if((p->as == ABSR || p->as == ARTS) && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s in %s", s->name, TNAME);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range in %s\n%P", TNAME, p);
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ long dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != ABRA)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+void
+dostkoff(void)
+{
+ Prog *p, *q, *qq;
+ long s, t;
+ int a;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f stkoff\n", cputime());
+ Bflush(&bso);
+ s = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ s = p->to.offset;
+ if(s == 0)
+ continue;
+ p = nprg(p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = s;
+ p->stkoff = 0;
+ continue;
+ }
+ t = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as == ATEXT)
+ break;
+ if(q->stkoff >= 0)
+ if(q->stkoff != s)
+ diag("stack offset %ld is %ld sb %ld in %s\n%P",
+ q->pc, q->stkoff, s, TNAME, p);
+ q->stkoff = s;
+ if(t++ > 100) {
+ diag("loop in stack offset 1: %P", p);
+ break;
+ }
+ }
+ o = &optab[p->as];
+ if(p->to.type == D_TOS)
+ s -= o->dstsp;
+ if(p->from.type == D_TOS)
+ s -= o->srcsp;
+ if(p->as == AADJSP)
+ s += p->from.offset;
+ if(p->as == APEA)
+ s += 4;
+ t = 0;
+ for(q = p->link; q != P; q = q->pcond) {
+ if(q->as == ATEXT) {
+ q = P;
+ break;
+ }
+ if(q->stkoff >= 0)
+ break;
+ if(t++ > 100) {
+ diag("loop in stack offset 2: %P", p);
+ break;
+ }
+ }
+ if(q == P || q->stkoff == s)
+ continue;
+ if(p->as == ABRA || p->as == ARTS || p->as == ARTE) {
+ s = q->stkoff;
+ continue;
+ }
+ t = q->stkoff - s;
+ s = q->stkoff;
+ p = nprg(p);
+ p->as = AADJSP;
+ p->stkoff = s - t;
+ p->from.type = D_CONST;
+ p->from.offset = t;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f rewrite\n", cputime());
+ Bflush(&bso);
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ a = p->from.type & D_MASK;
+ if(a == D_AUTO)
+ p->from.offset += p->stkoff;
+ if(a == D_PARAM)
+ p->from.offset += p->stkoff + 4;
+ a = p->to.type & D_MASK;
+ if(a == D_AUTO)
+ p->to.offset += p->stkoff;
+ if(a == D_PARAM)
+ p->to.offset += p->stkoff + 4;
+ switch(p->as) {
+ default:
+ continue;
+
+ case AMOVW:
+ if(p->from.type != D_CCR)
+ continue;
+ a = p->to.type;
+ if((a < D_R0 || a > D_R0+7) && a != D_TOS)
+ diag("bad dest for MOVCC %P", p);
+ p->as = ALEA;
+ p->from.type = I_INDIR|(D_A0+7);
+ p->from.offset = -2;
+ p->to.type = D_A0+7;
+
+ p = nprg(p);
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = prog_ccr;
+ p->to.sym = prog_ccr->from.sym;
+
+ if(a != D_TOS) {
+ p = nprg(p);
+ p->as = AMOVW;
+ p->from.type = D_TOS;
+ p->to.type = a;
+ }
+ continue;
+
+ case AEXTBL:
+ a = p->to.type;
+ if(a < D_R0 || a > D_R0+7)
+ diag("bad dest for EXTB");
+ p->as = AEXTBW;
+
+ p = nprg(p);
+ p->as = AEXTWL;
+ p->to.type = a;
+ continue;
+
+ case AMULSL:
+ case AMULUL:
+ qq = prog_mull;
+ goto mdcom;
+ case ADIVSL:
+ qq = prog_divsl;
+ goto mdcom;
+ case ADIVUL:
+ qq = prog_divul;
+ mdcom:
+ if(debug['m'])
+ continue;
+ a = p->to.type;
+ if(a < D_R0 || a > D_R0+7)
+ diag("bad dest for mul/div");
+ p->as = AMOVL;
+ p->to.type = D_TOS;
+
+ p = nprg(p);
+ p->as = AMOVL;
+ p->from.type = a;
+ p->to.type = D_TOS;
+
+ p = nprg(p);
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = qq;
+ p->to.sym = qq->from.sym;
+
+ p = nprg(p);
+ p->as = AMOVL;
+ p->from.type = D_TOS;
+ p->to.type = a;
+
+ p = nprg(p);
+ p->as = AMOVL;
+ p->from.type = D_TOS;
+ p->to.type = a+1;
+ if(qq == prog_mull)
+ p->to.type = a;
+ continue;
+
+ case ARTS:
+ break;
+ }
+ if(p->stkoff == 0)
+ continue;
+
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -p->stkoff;
+
+ p = nprg(p);
+ p->as = ARTS;
+ p->stkoff = 0;
+ }
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+void
+initmuldiv1(void)
+{
+ lookup("_mull", 0)->type = SXREF;
+ lookup("_divsl", 0)->type = SXREF;
+ lookup("_divul", 0)->type = SXREF;
+ lookup("_ccr", 0)->type = SXREF;
+}
+
+void
+initmuldiv2(void)
+{
+ Sym *s1, *s2, *s3, *s4;
+ Prog *p;
+
+ if(prog_mull != P)
+ return;
+ s1 = lookup("_mull", 0);
+ s2 = lookup("_divsl", 0);
+ s3 = lookup("_divul", 0);
+ s4 = lookup("_ccr", 0);
+ for(p = firstp; p != P; p = p->link)
+ if(p->as == ATEXT) {
+ if(p->from.sym == s1)
+ prog_mull = p;
+ if(p->from.sym == s2)
+ prog_divsl = p;
+ if(p->from.sym == s3)
+ prog_divul = p;
+ if(p->from.sym == s4)
+ prog_ccr = p;
+ }
+ if(prog_mull == P) {
+ diag("undefined: %s", s1->name);
+ prog_mull = curtext;
+ }
+ if(prog_divsl == P) {
+ diag("undefined: %s", s2->name);
+ prog_divsl = curtext;
+ }
+ if(prog_divul == P) {
+ diag("undefined: %s", s3->name);
+ prog_divul = curtext;
+ }
+ if(prog_ccr == P) {
+ diag("undefined: %s", s4->name);
+ prog_ccr = curtext;
+ }
+}
diff --git a/sys/src/cmd/1l/span.c b/sys/src/cmd/1l/span.c
new file mode 100755
index 000000000..d8baa3625
--- /dev/null
+++ b/sys/src/cmd/1l/span.c
@@ -0,0 +1,515 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ long v, c, idat;
+ Optab *o;
+ int m, n;
+
+ xdefine("etext", STEXT, 0L);
+ xdefine("a6base", STEXT, 0L);
+ idat = INITDAT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ n = 0;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_A0+7;
+ v = -p->from.offset;
+ p->from.offset = v;
+ if((v < -8 && v >= -32768L) || (v > 8 && v < 32768L)) {
+ p->as = ALEA;
+ p->from.type = I_INDIR | (D_A0+7);
+ continue;
+ }
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v >= 0 && v <= 8)
+ p->from.type = D_QUICK;
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+ n = 0;
+
+start:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ o = &optab[p->as];
+ p->pc = c;
+ m = mmsize[o->optype];
+ if(m == 0) {
+ if(p->as == AWORD)
+ m = 2;
+ if(p->as == ALONG)
+ m = 4;
+ p->mark = m;
+ c += m;
+ continue;
+ }
+ if(p->from.type != D_NONE)
+ m += andsize(p, &p->from);
+ if(p->to.type == D_BRANCH) {
+ if(p->pcond == P)
+ p->pcond = p;
+ c += m;
+ if(m == 2)
+ m |= 0100;
+ p->mark = m;
+ continue;
+ }
+ if(p->to.type != D_NONE)
+ m += andsize(p, &p->to);
+ p->mark = m;
+ c += m;
+ }
+
+loop:
+ n++;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span %d\n", cputime(), n);
+ Bflush(&bso);
+ if(n > 60) {
+ diag("span must be looping");
+ errorexit();
+ }
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if((m = p->mark) & 0100) {
+ q = p->pcond;
+ v = q->pc - 2;
+ if(p->back)
+ v -= c;
+ else
+ v -= p->pc;
+ p->pc = c;
+ if(v < -32768L || v >= 32768L) {
+ c += 6; /* only jsr and jmp can do this */
+ } else
+ if(v < -128 || v >= 128)
+ c += 4;
+ else
+ if(v == 0) {
+ c += 4;
+ p->mark = 4;
+ } else
+ c += 2;
+ continue;
+ }
+ p->pc = c;
+ c += m;
+ }
+ if(c != textsize) {
+ textsize = c;
+ goto loop;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(INITDAT != idat) {
+ idat = INITDAT;
+ goto start;
+ }
+ xdefine("etext", STEXT, c);
+ xdefine("a6base", STEXT, INITDAT+A6OFFSET);
+ if(debug['v'])
+ Bprint(&bso, "etext = %lux\n", c);
+ Bflush(&bso);
+ for(p = textp; p != P; p = p->pcond)
+ p->from.sym->value = p->pc;
+ textsize = c - INITTEXT;
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+ if(s->type == STEXT && s->value == 0)
+ s->value = v;
+}
+
+int
+andsize(Prog *p, Adr *ap)
+{
+ int t, n;
+ long v;
+ Optab *o;
+
+ t = ap->type;
+ n = simple[t];
+ if(n != 0177) {
+ v = ap->offset;
+ if(v == 0)
+ return 0;
+ if((n&070) != 020) /* D_INDIR */
+ return 0;
+ if(v == 0)
+ return 0;
+ return 2;
+ }
+ if((t&I_MASK) == I_ADDR)
+ t = D_CONST;
+ switch(t) {
+
+ default:
+ return 0;
+
+ case D_STACK:
+ case D_AUTO:
+ case D_PARAM:
+ v = ap->offset;
+ if(v == 0)
+ return 0;
+ return 2;
+
+ case I_INDIR|D_CONST:
+ v = ap->offset;
+ if(v < -32768L || v >= 32768L)
+ return 4;
+ return 2;
+
+ case D_STATIC:
+ case D_EXTERN:
+ if(ap->sym->type == STEXT) {
+ if(HEADTYPE == 4)
+ return 2;
+ return 4;
+ }
+ v = ap->sym->value + ap->offset - A6OFFSET;
+ if(v == 0)
+ return 0;
+ if(v < -32768L || v >= 32768L)
+ return 4;
+ return 2;
+
+ case D_CONST:
+ case D_FCONST:
+ o = &optab[p->as];
+ if(ap == &(p->from))
+ return o->srcsp;
+ return o->dstsp;
+
+ case D_CCR:
+ case D_SR:
+ if(p->as == AMOVW)
+ return 0;
+ return 2;
+
+ case D_USP:
+ t = p->from.type;
+ if(t >= D_A0 && t <= D_A0+8)
+ return 0;
+ t = p->to.type;
+ if(t >= D_A0 && t <= D_A0+8)
+ return 0;
+
+ case D_SFC:
+ case D_DFC:
+ case D_CACR:
+ case D_VBR:
+ case D_CAAR:
+ case D_MSP:
+ case D_ISP:
+ case D_FPCR:
+ case D_FPSR:
+ case D_FPIAR:
+ case D_TC:
+ case D_ITT0:
+ case D_ITT1:
+ case D_DTT0:
+ case D_DTT1:
+ case D_MMUSR:
+ case D_URP:
+ case D_SRP:
+ return 2;
+ }
+}
+
+void
+putsymb(Sym *s, int t, long v)
+{
+ int i, f;
+ char *n;
+
+ n = s->name;
+ if(t == 'f')
+ n++;
+ lput(v);
+ if(s->version)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(n[0]);
+ for(i=1; n[i] != 0 || n[i+1] != 0; i += 2) {
+ CPUT(n[i]);
+ CPUT(n[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; n[i]; i++)
+ CPUT(n[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; n[i] != 0 || n[i+1] != 0; i+=2) {
+ f = ((n[i]&0xff) << 8) | (n[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(s->version)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, n, s->version);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, n);
+ }
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s, 'T', s->value);
+ s = lookup("a6base", 0);
+ if(s->type == STEXT)
+ putsymb(s, 'D', s->value);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SDATA:
+ putsymb(s, 'D', s->value+INITDAT);
+ continue;
+
+ case SBSS:
+ putsymb(s, 'B', s->value+INITDAT);
+ continue;
+
+ case SFILE:
+ putsymb(s, 'f', s->value);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->pcond) {
+ s = p->from.sym;
+ if(s->type != STEXT)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym, 'z', a->aoffset);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym, 'Z', a->aoffset);
+
+ putsymb(s, 'T', s->value);
+
+ /* auto and param after */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym, 'a', -a->aoffset);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym, 'p', a->aoffset);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+#define MINLC 2
+void
+asmsp(void)
+{
+ long oldpc, oldsp;
+ Prog *p;
+ int s;
+ long v;
+
+ oldpc = INITTEXT;
+ oldsp = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->stkoff == oldsp || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['G'])
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ continue;
+ }
+ if(debug['G'])
+ Bprint(&bso, "\t\t%6ld", spsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['G'])
+ Bprint(&bso, " pc+%d*2(%d)", s, s+128);
+ v -= s;
+ spsize++;
+ }
+ v = p->stkoff - oldsp;
+ oldsp = p->stkoff;
+ oldpc = p->pc + MINLC;
+ if(v & 3 || v > 64L*4L || v < -64L*4L) {
+ CPUT(0); /* 0 vvvv +sp */
+ lput(v);
+ if(debug['G']) {
+ if(v > 0)
+ Bprint(&bso, " sp+%ld*1(%d,%ld)\n",
+ v, 0, v);
+ else
+ Bprint(&bso, " sp%ld*1(%d,%ld)\n",
+ v, 0, v);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ spsize += 5;
+ continue;
+ }
+ s = v/4;
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +sp */
+ if(debug['G']) {
+ Bprint(&bso, " sp+%d*4(%d)\n", s, 0+s);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -sp */
+ if(debug['G']) {
+ Bprint(&bso, " sp%d*4(%d)\n", s, 64-s);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ }
+ spsize++;
+ }
+ while(spsize & 1) {
+ s = 129;
+ CPUT(s);
+ spsize++;
+ }
+ if(debug['v'] || debug['G'])
+ Bprint(&bso, "stsize = %ld\n", spsize);
+ Bflush(&bso);
+}
+
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}