home *** CD-ROM | disk | FTP | other *** search
- #include <sys/cachectl.h>
- #include <a.out.h>
- #include <unistd.h>
- #include <string.h>
- #include "pico.h"
-
- typedef unsigned long Inst;
-
- static void gen(Tree *t);
- static void binop(Tree *t, int s1, int s2, int d);
- static void binconst(Tree *t, int s1, int s2, int d);
- static void dodump(Inst *, int);
- static void clearregs(void);
- static void freereg(int);
- static int findreg(void);
-
- static Inst *code;
- static boolean, last = 8, regs[8], spp, sppmax, result;
-
- #define zero 0
- #define tmp 1
- #define base 4 /* first arg */
- #define offset 5 /* second arg */
- #define rx 16 /* first saved reg */
- #define ry 17
- #define sp 29
- #define ra 31
-
- #define RTYPE(a,b,c,d) (d|(c<<11)|(b<<16)|(a<<21))
- #define STYPE(a,b,c,d) (d|(c<<11)|(b<<6)|(a<<16))
- #define ITYPE(a,b,c,d) ((d<<26)|(a<<21)|(b&0xffff)|(c<<16))
-
- #define _ADDU(a,b,c) *code++ = RTYPE(a,b,c,041)
- #define _SUBU(a,b,c) *code++ = RTYPE(a,b,c,043)
- #define _MULTU(a,b) *code++ = RTYPE(a,b,0,031)
- #define _DIVU(a,b) *code++ = RTYPE(a,b,0,033)
- #define _MFLO(a) *code++ = RTYPE(0,0,a,022)
- #define _MFHI(a) *code++ = RTYPE(0,0,a,020)
- #define _SLTU(a,b,c) *code++ = RTYPE(a,b,c,053)
- #define _XOR(a,b,c) *code++ = RTYPE(a,b,c,046)
- #define _OR(a,b,c) *code++ = RTYPE(a,b,c,045)
- #define _NOR(a,b,c) *code++ = RTYPE(a,b,c,047)
- #define _AND(a,b,c) *code++ = RTYPE(a,b,c,044)
- #define _ANDI(a,b,c) *code++ = ITYPE(a,b,c,014)
- #define _XORI(a,b,c) *code++ = ITYPE(a,b,c,016)
- #define _ORI(a,b,c) *code++ = ITYPE(a,b,c,015)
- #define _ADDIU(a,b,c) *code++ = ITYPE(a,b,c,011)
- #define _SLTIU(a,b,c) *code++ = ITYPE(a,b,c,013)
- #define _LBU(a,b,c) *code++ = ITYPE(b,c,a,044)
- #define _SB(a,b,c) *code++ = ITYPE(b,c,a,050)
- #define _LW(a,b,c) *code++ = ITYPE(b,c,a,043)
- #define _SW(a,b,c) *code++ = ITYPE(b,c,a,053)
- #define _LUI(a,b) *code++ = ITYPE(0,b,a,017)
- #define _BNE(a,b,c) ITYPE(b,c,a,005)
- #define _BEQ(a,b,c) ITYPE(b,c,a,004)
- #define _JR(a) *code++ = RTYPE(a,0,0,010)
- #define _SLL(a,b,c) *code++ = STYPE(a,b,c,000)
- #define _SRL(a,b,c) *code++ = STYPE(a,b,c,002)
- #define _SRLV(a,b,c) *code++ = RTYPE(a,b,c,006)
- #define _SLLV(a,b,c) *code++ = RTYPE(b,a,c,004)
- #define _SRLV(a,b,c) *code++ = RTYPE(a,b,c,006)
- #define _NOP *code++ = 0x0
-
- #define _PUSH(a) {\
- _SW(a,sp,spp);\
- spp += 4;\
- if (spp > sppmax)\
- sppmax = spp;\
- }
-
- #define _POP(a) {\
- spp -= 4;\
- _LW(a,sp,spp);\
- }
-
- static void loadimm(int i, int j) {
- if (j < 0 && j >= -32768) {
- _ADDIU(zero,j,i);
- } else if ((Inst) j > 65535) {
- Inst k = (Inst) j >> 16;
- Inst l = (Inst) j & 65535;
- _LUI(i,k);
- if (l != 0)
- _ORI(i,l,i);
- } else {
- _ORI(zero,((Inst)j),i);
- }
- }
-
- extern void compile(Tree *t) {
- Inst prog[1024], *remem1, *remem2;
- void (*progp)() = (void (*)()) prog;
- code = prog;
- clearregs();
- last = findreg();
- code = prog;
- _ADDIU(sp,0,sp); /* value is or'ed in later */
- _PUSH(rx);
- _PUSH(ry);
- loadimm(ry,DEF_Y-1);
- remem1 = code;
- loadimm(rx,DEF_X-1);
- remem2 = code;
- gen(t);
- _ADDU(base,offset,tmp);
- _SB(result,tmp,0);
- _ADDIU(offset,-1,offset);
- *code = _BNE(zero,rx,remem2-code-1); code++;
- _ADDIU(rx,-1,rx);
- *code = _BNE(zero,ry,remem1-code-1); code++;
- _ADDIU(ry,-1,ry);
- _POP(ry);
- _POP(rx);
- _JR(ra);
- _ADDIU(sp,sppmax,sp);
- *prog |= (-sppmax)&0xffff;
- dodump(prog, (code - prog) * sizeof (Inst));
- cacheflush(prog, sizeof prog, ICACHE);
- progp(buf[0].data, (DEF_X*DEF_Y) - 1);
- }
-
- static void gen(Tree *t) {
- Inst *remem;
- int i, saved, b1, b2;
- switch (t->t) {
- case Num:
- if (t->i == 0) {
- result = zero;
- boolean = 1;
- } else {
- loadimm(result = last, t->i);
- boolean = !(t->i & ~1);
- }
- break;
- case Xcoord:
- result = rx;
- boolean = 0;
- break;
- case Ycoord:
- result = ry;
- boolean = 0;
- break;
- case Bang:
- gen(t->kids[0]);
- _SLTIU(result,1,last);
- result = last;
- boolean = 1;
- break;
- case Not:
- gen(t->kids[0]);
- _NOR(result,0,last);
- result = last;
- boolean = 0;
- break;
- case Neg:
- gen(t->kids[0]);
- _SUBU(zero,result,last);
- result = last;
- boolean = 0;
- break;
- case Cond:
- gen(t->kids[0]); /* test */
- remem = code;
- *code++ = _BEQ(zero,result,0);
- _NOP;
- gen(t->kids[1]); /* iftrue */
- b1 = boolean;
- if (result != last)
- _ADDU(result,zero,last);
- *remem |= code - remem;
- remem = code - 1;
- *code = code[-1];
- code[-1] = _BEQ(zero,zero,0); /* fill delay slot */
- code++;
- gen(t->kids[2]); /* iffalse */
- b2 = boolean;
- if (result != last)
- _ADDU(result,zero,last);
- result = last;
- boolean = (b1 & b2);
- *remem |= code - remem - 1;
- break;
- case Andalso:
- case Orelse:
- gen(t->kids[0]);
- b1 = boolean;
- if (result != last)
- _ADDU(result,zero,last);
- saved = last;
- remem = code;
- if (t->t == Andalso)
- *code++ = _BEQ(zero,last,0);
- else
- *code++ = _BNE(zero,last,0);
- _NOP;
- gen(t->kids[1]);
- b2 = boolean;
- if (result != saved)
- _ADDU(result,zero,saved);
- *remem |= code - remem - 1;
- if (!(b1&b2))
- _SLTU(zero,last,last); /* "normalize" expr to {0,1} */
- result = saved;
- boolean = 1;
- break;
- case Coordpair:
- if (t->i > nfiles || t->i < 0)
- error("no such buffer");
- if (t->kids[0] != NULL) {
- gen(t->kids[0]);
- i = last;
- } else
- i = offset;
- loadimm(tmp,(int)buf[t->i].data);
- _ADDU(tmp,i,last);
- _LBU(last,last,0);
- _NOP;
- result = last;
- boolean = 0;
- break;
- default:
- gen(t->kids[0]);
- saved = result;
- if (((Tree *)t->kids[1])->t == Num && (i = ((Tree *)t->kids[1])->i) < 32768 && i > -32768) {
- binconst(t,result,i,last);
- } else {
- if (saved != rx && saved != ry && (last = findreg()) == -1) {
- last = saved;
- saved = -1;
- _PUSH(last);
- }
- gen(t->kids[1]);
- if (saved == -1) {
- _POP(tmp);
- _NOP;
- binop(t,tmp,result,last);
- } else {
- binop(t,saved,result,last);
- if (saved != rx && saved != ry)
- freereg(saved);
- }
- }
- result = last;
- }
- }
-
- static void binop(Tree *t, int s1, int s2, int d) {
- boolean = 0;
- switch (t->t) {
- default:
- error("not a binop in binop!");
- case Add:
- _ADDU(s1,s2,d);
- break;
- case Sub:
- _SUBU(s1,s2,d);
- break;
- case Mult:
- _MULTU(s1,s2);
- _MFLO(d);
- break;
- case Div:
- _DIVU(s1,s2);
- _MFLO(d);
- break;
- case Mod:
- _DIVU(s1,s2);
- _MFHI(d);
- break;
- case Gt:
- _SLTU(s2,s1,d);
- boolean = 1;
- break;
- case Lt:
- _SLTU(s1,s2,d);
- boolean = 1;
- break;
- case Ge:
- _SLTU(s1,s2,d);
- _XORI(d,1,d);
- boolean = 1;
- break;
- case Le:
- _SLTU(s2,s1,d);
- _XORI(d,1,d);
- boolean = 1;
- break;
- case Eq:
- _XOR(s1,s2,d);
- _SLTIU(d,1,d);
- boolean = 1;
- break;
- case Ne:
- _XOR(s1,s2,d);
- _SLTIU(d,0,d);
- boolean = 1;
- break;
- case Xor:
- _XOR(s1,s2,d);
- break;
- case And:
- _AND(s1,s2,d);
- break;
- case Or:
- _OR(s1,s2,d);
- break;
- case Ll:
- _SLLV(s1,s2,d);
- break;
- case Rr:
- _SRLV(s1,s2,d);
- break;
- }
- }
-
- static void binconst(Tree *t, int s1, int s2, int d) {
- int shift;
- boolean = 0;
- switch (t->t) {
- default:
- error("not a binop in binconst!");
- case Add:
- _ADDIU(s1,s2,d);
- break;
- case Sub:
- _ADDIU(s1,-s2,d);
- break;
- case Mult:
- case Div:
- if (s2 < 0 || s2 & (s2 - 1) != 0) {
- loadimm(tmp,s2);
- if (t->t == Mult)
- _MULTU(s1,tmp);
- else
- _DIVU(s1,tmp);
- _MFLO(d);
- } else {
- for (shift = 0; s2 != 0; shift++, s2 >>= 1)
- ;
- if (shift == 0) {
- if (t->t == Mult)
- loadimm(d,0);
- else
- error("division by zero");
- return;
- } else if (t->t == Mult) {
- _SLL(s1,--shift,d);
- } else {
- _SRL(s1,--shift,d);
- }
- }
- break;
- case Mod:
- loadimm(tmp,s2);
- _DIVU(s1,tmp);
- _MFHI(d);
- break;
- case Gt:
- if (s2 != 0) {
- loadimm(tmp,s2);
- _SLTU(tmp,s1,d);
- } else
- _SLTU(zero,s1,d);
- boolean = 1;
- break;
- case Lt:
- _SLTIU(s1,s2,d);
- boolean = 1;
- break;
- case Ge:
- _SLTIU(s1,s2,d);
- _XORI(d,1,d);
- boolean = 1;
- break;
- case Le:
- if (s2 != 0) {
- loadimm(tmp,s2);
- _SLTU(tmp,s1,d);
- } else
- _SLTU(zero,s1,d);
- _XORI(d,1,d);
- boolean = 1;
- break;
- case Eq:
- if (s2 != 0) {
- _XORI(s1,s2,d);
- _SLTIU(d,1,d);
- } else
- _SLTIU(s1,1,d);
- boolean = 1;
- break;
- case Ne:
- if (s2 != 0) {
- _XORI(s1,s2,d);
- _SLTIU(d,0,d);
- } else
- _SLTIU(s1,0,d);
- boolean = 1;
- break;
- case Xor:
- _XORI(s1,s2,d);
- break;
- case And:
- _ANDI(s1,s2,d);
- break;
- case Or:
- _ORI(s1,s2,d);
- break;
- case Ll:
- _SLL(s1,s2,d);
- break;
- case Rr:
- _SRL(s1,s2,d);
- break;
- }
- }
-
- static void dodump(Inst *prog, int size) {
- if (debug) {
- struct filehdr f;
- struct scnhdr s;
- int fd = creat(DUMPFILE, 0644);
- if (fd < 0) {
- perror(DUMPFILE);
- exit(1);
- }
- f.f_magic = MIPSEBMAGIC;
- f.f_nscns = 1;
- f.f_timdat = 0;
- f.f_symptr = 0;
- f.f_nsyms = 0;
- f.f_opthdr = 0;
- f.f_flags = F_RELFLG | F_EXEC | F_LNNO | F_LSYMS | F_MINMAL;
- strcpy(s.s_name, ".text");
- s.s_paddr = 0;
- s.s_vaddr = 0;
- s.s_size = size;
- s.s_scnptr = sizeof s + sizeof f;
- s.s_relptr = 0;
- s.s_lnnoptr = 0;
- s.s_nreloc = 0;
- s.s_nlnno = 0;
- s.s_flags = 0;
- write(fd, &f, sizeof f);
- write(fd, &s, sizeof s);
- write(fd, prog, size);
- close(fd);
- }
- }
-
- static void clearregs() {
- int i;
- for (i = 0; i < 8; i++)
- regs[i] = 0;
- }
-
- static void freereg(int i) {
- regs[i-8] = 0;
- }
-
- static int findreg() {
- int i;
- for (i = 0; i < 8; i++)
- if (regs[i] == 0)
- break;
- if (i == 8)
- return -1;
- regs[i] = 1;
- return i+8;
- }
-