524 lines
9.9 KiB
C
524 lines
9.9 KiB
C
#include "l.h"
|
|
|
|
void
|
|
span(void)
|
|
{
|
|
Prog *p;
|
|
Sym *setext;
|
|
Optab *o;
|
|
int m;
|
|
long c;
|
|
|
|
if(debug['v'])
|
|
Bprint(&bso, "%5.2f span\n", cputime());
|
|
Bflush(&bso);
|
|
c = INITTEXT;
|
|
for(p = firstp; p != P; p = p->link) {
|
|
p->pc = c;
|
|
o = oplook(p);
|
|
m = o->size;
|
|
if(m == 0) {
|
|
if(p->as == ATEXT) {
|
|
curtext = p;
|
|
autosize = p->to.offset + 4;
|
|
if(p->from.sym != S)
|
|
p->from.sym->value = c;
|
|
continue;
|
|
}
|
|
if(p->as != ANOP)
|
|
diag("zero-width instruction\n%P", p);
|
|
continue;
|
|
}
|
|
c += m;
|
|
}
|
|
c = rnd(c, 8);
|
|
|
|
setext = lookup("etext", 0);
|
|
if(setext != S) {
|
|
setext->value = c;
|
|
textsize = c - INITTEXT;
|
|
}
|
|
if(INITRND)
|
|
INITDAT = rnd(c, INITRND);
|
|
if(debug['v'])
|
|
Bprint(&bso, "tsize = %lux\n", textsize);
|
|
Bflush(&bso);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
long
|
|
regoff(Adr *a)
|
|
{
|
|
|
|
instoffset = 0;
|
|
aclass(a);
|
|
return instoffset;
|
|
}
|
|
|
|
int
|
|
aclass(Adr *a)
|
|
{
|
|
Sym *s;
|
|
int t;
|
|
|
|
switch(a->type) {
|
|
case D_NONE:
|
|
return C_NONE;
|
|
|
|
case D_REG:
|
|
return C_REG;
|
|
|
|
case D_FREG:
|
|
return C_FREG;
|
|
|
|
case D_CREG:
|
|
return C_CREG;
|
|
|
|
case D_PREG:
|
|
if(a->reg == D_FSR)
|
|
return C_FSR;
|
|
if(a->reg == D_FPQ)
|
|
return C_FQ;
|
|
return C_PREG;
|
|
|
|
case D_OREG:
|
|
switch(a->name) {
|
|
case D_EXTERN:
|
|
case D_STATIC:
|
|
if(a->sym == S)
|
|
break;
|
|
t = a->sym->type;
|
|
if(t == 0 || t == SXREF) {
|
|
diag("undefined external: %s in %s",
|
|
a->sym->name, TNAME);
|
|
a->sym->type = SDATA;
|
|
}
|
|
instoffset = a->sym->value + a->offset - BIG;
|
|
if(instoffset >= -BIG && instoffset < BIG) {
|
|
if(instoffset & 7)
|
|
return C_OSEXT;
|
|
return C_ESEXT;
|
|
}
|
|
if(instoffset & 7)
|
|
return C_OLEXT;
|
|
return C_ELEXT;
|
|
case D_AUTO:
|
|
instoffset = autosize + a->offset;
|
|
goto dauto;
|
|
|
|
case D_PARAM:
|
|
instoffset = autosize + a->offset + 4L;
|
|
dauto:
|
|
if(instoffset >= -BIG && instoffset < BIG) {
|
|
if(instoffset & 7)
|
|
return C_OSAUTO;
|
|
return C_ESAUTO;
|
|
}
|
|
if(instoffset & 7)
|
|
return C_OLAUTO;
|
|
return C_ELAUTO;
|
|
case D_NONE:
|
|
instoffset = a->offset;
|
|
if(instoffset == 0)
|
|
return C_ZOREG;
|
|
if(instoffset >= -BIG && instoffset < BIG)
|
|
return C_SOREG;
|
|
return C_LOREG;
|
|
}
|
|
return C_GOK;
|
|
|
|
case D_ASI:
|
|
if(a->name == D_NONE)
|
|
return C_ASI;
|
|
return C_GOK;
|
|
|
|
case D_CONST:
|
|
switch(a->name) {
|
|
|
|
case D_NONE:
|
|
instoffset = a->offset;
|
|
consize:
|
|
if(instoffset == 0)
|
|
return C_ZCON;
|
|
if(instoffset >= -0x1000 && instoffset <= 0xfff)
|
|
return C_SCON;
|
|
if((instoffset & 0x3ff) == 0)
|
|
return C_UCON;
|
|
return C_LCON;
|
|
|
|
case D_EXTERN:
|
|
case D_STATIC:
|
|
s = a->sym;
|
|
if(s == S)
|
|
break;
|
|
t = s->type;
|
|
if(t == 0 || t == SXREF) {
|
|
diag("undefined external: %s in %s",
|
|
s->name, TNAME);
|
|
s->type = SDATA;
|
|
}
|
|
if(s->type == STEXT || s->type == SLEAF) {
|
|
instoffset = s->value + a->offset;
|
|
return C_LCON;
|
|
}
|
|
if(s->type == SCONST) {
|
|
instoffset = s->value + a->offset;
|
|
goto consize;
|
|
}
|
|
instoffset = s->value + a->offset - BIG;
|
|
if(instoffset >= -BIG && instoffset < BIG && instoffset != 0)
|
|
return C_SECON;
|
|
instoffset = s->value + a->offset + INITDAT;
|
|
/* not sure why this barfs */
|
|
return C_LCON;
|
|
/*
|
|
if(instoffset == 0)
|
|
return C_ZCON;
|
|
if(instoffset >= -0x1000 && instoffset <= 0xfff)
|
|
return C_SCON;
|
|
if((instoffset & 0x3ff) == 0)
|
|
return C_UCON;
|
|
return C_LCON;
|
|
*/
|
|
|
|
case D_AUTO:
|
|
instoffset = autosize + a->offset;
|
|
if(instoffset >= -BIG && instoffset < BIG)
|
|
return C_SACON;
|
|
return C_LACON;
|
|
|
|
case D_PARAM:
|
|
instoffset = autosize + a->offset + 4L;
|
|
if(instoffset >= -BIG && instoffset < BIG)
|
|
return C_SACON;
|
|
return C_LACON;
|
|
}
|
|
return C_GOK;
|
|
|
|
case D_BRANCH:
|
|
return C_SBRA;
|
|
}
|
|
return C_GOK;
|
|
}
|
|
|
|
Optab*
|
|
oplook(Prog *p)
|
|
{
|
|
int a1, a2, a3, r;
|
|
char *c1, *c3;
|
|
Optab *o, *e;
|
|
|
|
a1 = p->optab;
|
|
if(a1)
|
|
return optab+(a1-1);
|
|
a1 = p->from.class;
|
|
if(a1 == 0) {
|
|
a1 = aclass(&p->from) + 1;
|
|
p->from.class = a1;
|
|
}
|
|
a1--;
|
|
a3 = p->to.class;
|
|
if(a3 == 0) {
|
|
a3 = aclass(&p->to) + 1;
|
|
p->to.class = a3;
|
|
}
|
|
a3--;
|
|
a2 = C_NONE;
|
|
if(p->reg != NREG)
|
|
a2 = C_REG;
|
|
r = p->as;
|
|
o = oprange[r].start;
|
|
if(o == 0)
|
|
o = oprange[r].stop; /* just generate an error */
|
|
e = oprange[r].stop;
|
|
c1 = xcmp[a1];
|
|
c3 = xcmp[a3];
|
|
for(; o<e; o++)
|
|
if(o->a2 == a2)
|
|
if(c1[o->a1])
|
|
if(c3[o->a3]) {
|
|
p->optab = (o-optab)+1;
|
|
return o;
|
|
}
|
|
diag("illegal combination %A %d %d %d",
|
|
p->as, a1, a2, a3);
|
|
if(1||!debug['a'])
|
|
prasm(p);
|
|
if(o == 0)
|
|
errorexit();
|
|
return o;
|
|
}
|
|
|
|
int
|
|
cmp(int a, int b)
|
|
{
|
|
|
|
if(a == b)
|
|
return 1;
|
|
switch(a) {
|
|
case C_LCON:
|
|
if(b == C_ZCON || b == C_SCON || b == C_UCON)
|
|
return 1;
|
|
break;
|
|
case C_UCON:
|
|
if(b == C_ZCON)
|
|
return 1;
|
|
break;
|
|
case C_SCON:
|
|
if(b == C_ZCON)
|
|
return 1;
|
|
break;
|
|
case C_LACON:
|
|
if(b == C_SACON)
|
|
return 1;
|
|
break;
|
|
case C_LBRA:
|
|
if(b == C_SBRA)
|
|
return 1;
|
|
break;
|
|
case C_ELEXT:
|
|
if(b == C_ESEXT)
|
|
return 1;
|
|
break;
|
|
case C_LEXT:
|
|
if(b == C_SEXT ||
|
|
b == C_ESEXT || b == C_OSEXT ||
|
|
b == C_ELEXT || b == C_OLEXT)
|
|
return 1;
|
|
break;
|
|
case C_SEXT:
|
|
if(b == C_ESEXT || b == C_OSEXT)
|
|
return 1;
|
|
break;
|
|
case C_ELAUTO:
|
|
if(b == C_ESAUTO)
|
|
return 1;
|
|
break;
|
|
case C_LAUTO:
|
|
if(b == C_SAUTO ||
|
|
b == C_ESAUTO || b == C_OSAUTO ||
|
|
b == C_ELAUTO || b == C_OLAUTO)
|
|
return 1;
|
|
break;
|
|
case C_SAUTO:
|
|
if(b == C_ESAUTO || b == C_OSAUTO)
|
|
return 1;
|
|
break;
|
|
case C_REG:
|
|
if(b == C_ZCON)
|
|
return 1;
|
|
break;
|
|
case C_LOREG:
|
|
if(b == C_ZOREG || b == C_SOREG)
|
|
return 1;
|
|
break;
|
|
case C_SOREG:
|
|
if(b == C_ZOREG)
|
|
return 1;
|
|
break;
|
|
|
|
case C_ANY:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ocmp(const void *a1, const void *a2)
|
|
{
|
|
Optab *p1, *p2;
|
|
int n;
|
|
|
|
p1 = (Optab*)a1;
|
|
p2 = (Optab*)a2;
|
|
n = p1->as - p2->as;
|
|
if(n)
|
|
return n;
|
|
n = p1->a1 - p2->a1;
|
|
if(n)
|
|
return n;
|
|
n = p1->a2 - p2->a2;
|
|
if(n)
|
|
return n;
|
|
n = p1->a3 - p2->a3;
|
|
if(n)
|
|
return n;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
buildop(void)
|
|
{
|
|
int i, n, r;
|
|
|
|
for(i=0; i<C_NCLASS; i++)
|
|
for(n=0; n<C_NCLASS; n++)
|
|
xcmp[i][n] = cmp(n, i);
|
|
for(n=0; optab[n].as != AXXX; n++)
|
|
;
|
|
qsort(optab, n, sizeof(optab[0]), ocmp);
|
|
for(i=0; i<n; i++) {
|
|
r = optab[i].as;
|
|
oprange[r].start = optab+i;
|
|
while(optab[i].as == r)
|
|
i++;
|
|
oprange[r].stop = optab+i;
|
|
i--;
|
|
|
|
switch(r)
|
|
{
|
|
default:
|
|
diag("unknown op in build: %A", r);
|
|
errorexit();
|
|
case AADD:
|
|
oprange[AADDX] = oprange[r];
|
|
oprange[ASUB] = oprange[r];
|
|
oprange[ASUBX] = oprange[r];
|
|
oprange[AMUL] = oprange[r];
|
|
oprange[AXOR] = oprange[r];
|
|
oprange[AXNOR] = oprange[r];
|
|
oprange[AAND] = oprange[r];
|
|
oprange[AANDN] = oprange[r];
|
|
oprange[AOR] = oprange[r];
|
|
oprange[AORN] = oprange[r];
|
|
oprange[ASLL] = oprange[r];
|
|
oprange[ASRL] = oprange[r];
|
|
oprange[ASRA] = oprange[r];
|
|
oprange[AADDCC] = oprange[r];
|
|
oprange[AADDXCC] = oprange[r];
|
|
oprange[ATADDCC] = oprange[r];
|
|
oprange[ATADDCCTV] = oprange[r];
|
|
oprange[ASUBCC] = oprange[r];
|
|
oprange[ASUBXCC] = oprange[r];
|
|
oprange[ATSUBCC] = oprange[r];
|
|
oprange[ATSUBCCTV] = oprange[r];
|
|
oprange[AXORCC] = oprange[r];
|
|
oprange[AXNORCC] = oprange[r];
|
|
oprange[AANDCC] = oprange[r];
|
|
oprange[AANDNCC] = oprange[r];
|
|
oprange[AORCC] = oprange[r];
|
|
oprange[AORNCC] = oprange[r];
|
|
oprange[AMULSCC] = oprange[r];
|
|
oprange[ASAVE] = oprange[r];
|
|
oprange[ARESTORE] = oprange[r];
|
|
break;
|
|
case AMOVB:
|
|
oprange[AMOVH] = oprange[r];
|
|
oprange[AMOVHU] = oprange[r];
|
|
oprange[AMOVBU] = oprange[r];
|
|
oprange[ASWAP] = oprange[r];
|
|
oprange[ATAS] = oprange[r];
|
|
break;
|
|
case ABA:
|
|
oprange[ABN] = oprange[r];
|
|
oprange[AFBA] = oprange[r];
|
|
oprange[AFBN] = oprange[r];
|
|
break;
|
|
case ABE:
|
|
oprange[ABCC] = oprange[r];
|
|
oprange[ABCS] = oprange[r];
|
|
oprange[ABGE] = oprange[r];
|
|
oprange[ABGU] = oprange[r];
|
|
oprange[ABG] = oprange[r];
|
|
oprange[ABLEU] = oprange[r];
|
|
oprange[ABLE] = oprange[r];
|
|
oprange[ABL] = oprange[r];
|
|
oprange[ABNEG] = oprange[r];
|
|
oprange[ABNE] = oprange[r];
|
|
oprange[ABPOS] = oprange[r];
|
|
oprange[ABVC] = oprange[r];
|
|
oprange[ABVS] = oprange[r];
|
|
|
|
oprange[AFBE] = oprange[r];
|
|
oprange[AFBG] = oprange[r];
|
|
oprange[AFBGE] = oprange[r];
|
|
oprange[AFBL] = oprange[r];
|
|
oprange[AFBLE] = oprange[r];
|
|
oprange[AFBLG] = oprange[r];
|
|
oprange[AFBNE] = oprange[r];
|
|
oprange[AFBO] = oprange[r];
|
|
oprange[AFBU] = oprange[r];
|
|
oprange[AFBUE] = oprange[r];
|
|
oprange[AFBUG] = oprange[r];
|
|
oprange[AFBUGE] = oprange[r];
|
|
oprange[AFBUL] = oprange[r];
|
|
oprange[AFBULE] = oprange[r];
|
|
break;
|
|
case ATA:
|
|
oprange[ATCC] = oprange[r];
|
|
oprange[ATCS] = oprange[r];
|
|
oprange[ATE] = oprange[r];
|
|
oprange[ATGE] = oprange[r];
|
|
oprange[ATGU] = oprange[r];
|
|
oprange[ATG] = oprange[r];
|
|
oprange[ATLEU] = oprange[r];
|
|
oprange[ATLE] = oprange[r];
|
|
oprange[ATL] = oprange[r];
|
|
oprange[ATNEG] = oprange[r];
|
|
oprange[ATNE] = oprange[r];
|
|
oprange[ATN] = oprange[r];
|
|
oprange[ATPOS] = oprange[r];
|
|
oprange[ATVC] = oprange[r];
|
|
oprange[ATVS] = oprange[r];
|
|
break;
|
|
case AFADDD:
|
|
oprange[AFADDF] = oprange[r];
|
|
oprange[AFADDX] = oprange[r];
|
|
oprange[AFDIVD] = oprange[r];
|
|
oprange[AFDIVF] = oprange[r];
|
|
oprange[AFDIVX] = oprange[r];
|
|
oprange[AFMULD] = oprange[r];
|
|
oprange[AFMULF] = oprange[r];
|
|
oprange[AFMULX] = oprange[r];
|
|
oprange[AFSUBD] = oprange[r];
|
|
oprange[AFSUBF] = oprange[r];
|
|
oprange[AFSUBX] = oprange[r];
|
|
break;
|
|
case AFCMPD:
|
|
oprange[AFCMPF] = oprange[r];
|
|
oprange[AFCMPX] = oprange[r];
|
|
oprange[AFCMPED] = oprange[r];
|
|
oprange[AFCMPEF] = oprange[r];
|
|
oprange[AFCMPEX] = oprange[r];
|
|
break;
|
|
case AFABSF:
|
|
oprange[AFMOVDF] = oprange[r];
|
|
oprange[AFMOVDW] = oprange[r];
|
|
oprange[AFMOVFD] = oprange[r];
|
|
oprange[AFMOVFW] = oprange[r];
|
|
oprange[AFMOVWD] = oprange[r];
|
|
oprange[AFMOVWF] = oprange[r];
|
|
oprange[AFNEGF] = oprange[r];
|
|
oprange[AFSQRTD] = oprange[r];
|
|
oprange[AFSQRTF] = oprange[r];
|
|
break;
|
|
case AFMOVF:
|
|
case AFMOVD:
|
|
case AMOVW:
|
|
case AMOVD:
|
|
case AWORD:
|
|
case ARETT:
|
|
case AJMPL:
|
|
case AJMP:
|
|
case ACMP:
|
|
case ANOP:
|
|
case ATEXT:
|
|
case ADIV:
|
|
case ADIVL:
|
|
case AMOD:
|
|
case AMODL:
|
|
break;
|
|
}
|
|
}
|
|
}
|