home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume26
/
pico
/
part01
/
mipsgen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-14
|
9KB
|
471 lines
#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;
}