1228 lines
25 KiB
C
1228 lines
25 KiB
C
# include "mfile2.h"
|
|
#ifndef NONAME
|
|
#define NONAME 040000
|
|
#endif
|
|
|
|
int rsmask;
|
|
|
|
/* the stack frame looks as follows:
|
|
**
|
|
** incoming args
|
|
** saved PC (4 bytes)
|
|
** saved old FP (rr12) (4 bytes)
|
|
** saved regs (rr10, rr8)
|
|
** autos (maxboff keeps track of this)
|
|
** temps (maxtemp keeps track of this)
|
|
** 2 byte field for offset to saved FP
|
|
** SP,FP->
|
|
** the first temp begins at FP + 2
|
|
** the last temp ends at FP + ~L1
|
|
** the first auto begins at FP + ~L1
|
|
** the last auto ends at FP + ~L2 - 12
|
|
** rr8 is saved at FP + ~L2 - 12
|
|
** rr10 is saved at FP + ~L2 - 8
|
|
** rr12 (the old FP) is saved at FP + ~L2 - 4
|
|
** the first arg begins at FP + ~L2 + 4
|
|
*/
|
|
|
|
static char rnm[5];
|
|
#define HIGHREG 0x40
|
|
#define NFLG 0x7
|
|
|
|
|
|
/* retun number of bytes for type t */
|
|
typlen(t)
|
|
{
|
|
if(t & (TLONG |TULONG| TPOINT | TFLOAT))
|
|
return(4);
|
|
else if (t & (TUCHAR | TCHAR))
|
|
return(1);
|
|
else if ( t & TDOUBLE)
|
|
return(8);
|
|
else
|
|
return(2);
|
|
}
|
|
|
|
char *
|
|
prnames(typ, val, lab)
|
|
register typ, val;
|
|
register lab;
|
|
{
|
|
char *s;
|
|
register int errorf;
|
|
if(rdebug > 2)
|
|
printf("typ = 0x%x val = %d lab = %d\n",typ,val,lab);
|
|
errorf = 0;
|
|
s = rnm;
|
|
*s = '?';
|
|
*(s+1) = '\0';
|
|
switch(typlen(typ))
|
|
{
|
|
case 1:
|
|
if((val & 0xf) > 7)
|
|
errorf = 1;
|
|
if(HIGHREG & val)
|
|
sprintf(s, "rh%d",(val & 0xf));
|
|
else sprintf(s, "rl%d",val);
|
|
break;
|
|
case 2:
|
|
if(lab==2)
|
|
goto lll;
|
|
if(lab==4)
|
|
goto ddd;
|
|
sss:
|
|
if(val > 11)
|
|
errorf = 1;
|
|
sprintf(s, "r%d",val);
|
|
break;
|
|
case 4:
|
|
if(lab==4)
|
|
goto ddd;
|
|
if(lab==1)
|
|
goto sss;
|
|
lll:
|
|
if(val & 1 || val > 11)
|
|
errorf = 1;
|
|
sprintf(s, "rr%d",val);
|
|
break;
|
|
case 8:
|
|
if(lab==2)
|
|
goto lll;
|
|
if(lab==1)
|
|
goto sss;
|
|
ddd:
|
|
if(val & 3 || val > 8)
|
|
errorf = 1;
|
|
sprintf(s, "rq%d",val);
|
|
break;
|
|
default:
|
|
werror("bad register type (length = %d)",typlen(typ));
|
|
}
|
|
if(errorf)
|
|
werror("bad register value %d, length = %d",val,
|
|
typlen(typ));
|
|
return s;
|
|
}
|
|
|
|
|
|
lineid( l, fn )
|
|
char *fn;
|
|
{
|
|
/* identify line l and file fn */
|
|
printf( "%s line %d, file %s\n", COMMENTSTR, l, fn );
|
|
}
|
|
|
|
eobl2()
|
|
{
|
|
register off;
|
|
register rsave;
|
|
register i, m;
|
|
/* count bits in rsmask */
|
|
for( rsave=i=0, m=1; i<16; ++i, m<<=1 )
|
|
{
|
|
if( m&rsmask ) rsave += 4;
|
|
}
|
|
maxboff /= SZCHAR;
|
|
maxtemp /= SZCHAR;
|
|
maxarg /= SZCHAR;
|
|
|
|
off = maxtemp + 2;
|
|
/* space for temps + 2 bytes for offset to old frame pointer */
|
|
printf("\t~L1 := %d\n", off);
|
|
off += maxboff; /* space for automatics */
|
|
off += 12; /* 12 bytes for saved registers */
|
|
printf("\t~L2 := %d\n\t}\n", off);
|
|
rsmask = 0;
|
|
eobl2dbg(); /* very end debug code */
|
|
}
|
|
|
|
special( sh, p )
|
|
NODE *p;
|
|
register sh;
|
|
{
|
|
register int val;
|
|
|
|
sh &= SVMASK; /* clear all but the special code */
|
|
switch (sh)
|
|
{
|
|
case 1: /* power of 2 */
|
|
case 2: /* sum of 2 powers of 2 */
|
|
case 3: /* difference of 2 powers of 2 */
|
|
|
|
if (p->tn.op != ICON || p->tn.name != (char *) 0)
|
|
return(0);
|
|
val = p->tn.lval;
|
|
if (sh == 1) /* power of 2 */
|
|
return (val > 0 && (val & (val-1)) == 0);
|
|
else if (sh == 2 && val > 0) /* sum of powers of 2 */
|
|
{
|
|
/* (word) multiply faster than shift by >12 on 68010 */
|
|
/* shift is always faster
|
|
if (!(p->tn.type & (TLONG | TULONG)) && val > 4096)
|
|
return(0);
|
|
*/
|
|
return ((val &= (val-1)) != 0 && (val & (val-1)) == 0);
|
|
}
|
|
else if (sh == 3 && val > 0) /* diff of powers of 2 */
|
|
{
|
|
/* (word) multiply faster than shift by >12 on 68010 */
|
|
/*
|
|
if (!(p->tn.type & (TLONG | TULONG)) && val > 4096)
|
|
return(0);
|
|
*/
|
|
while ((val & 1) == 0) /* get to '00..011...1' */
|
|
val >>= 1;
|
|
return ((val & (val+1)) == 0);
|
|
}
|
|
else
|
|
return(0);
|
|
break;
|
|
|
|
default:
|
|
e2print(p);
|
|
cerror( "special called!" );
|
|
return( INFINITY );
|
|
}
|
|
}
|
|
|
|
static int toff;
|
|
static int toffbase;
|
|
|
|
popargs( size )
|
|
register size;
|
|
{
|
|
/* pop arguments from the stack */
|
|
toff -= size/2;
|
|
if( toff == 0 )
|
|
{
|
|
size -= 2*toffbase;
|
|
toffbase = toff = 0;
|
|
}
|
|
if(!size)
|
|
return;
|
|
|
|
/*
|
|
printf( " add.l &%d,%%sp\n", size );
|
|
*/
|
|
if (size <= 16)
|
|
printf("\tinc\tsp,#%%%x\n", size);
|
|
else
|
|
printf("\tadd\tsp,#%%%x\n", (unsigned short)size);
|
|
}
|
|
|
|
|
|
/* print the address of p+d */
|
|
next_address( p, d, typ, flg)
|
|
register NODE *p;
|
|
register int d; /* the displacement */
|
|
register int typ;
|
|
{
|
|
register NODE *ptemp,*r,*l;
|
|
|
|
if (d) {
|
|
ptemp = talloc();
|
|
*ptemp= *p;
|
|
if(d == NFLG) d -= NFLG;
|
|
ptemp->tn.type = typ;
|
|
switch ( ptemp->in.op )
|
|
{
|
|
case REG:
|
|
ptemp->bn.label = typlen(typ)>>1;
|
|
if((!d)&&(typ == TCHAR))
|
|
ptemp->tn.rval |= HIGHREG;
|
|
ptemp->tn.rval += (d / 2);
|
|
break;
|
|
case TEMP: /* temps may be in registers */
|
|
if (ptemp->tn.rval)
|
|
goto bad;
|
|
/* else FALLTHRU */
|
|
case ICON:
|
|
if(p->in.name == (char *)0 && p->tn.rval == NONAME) {
|
|
if(typlen(typ)==2) {
|
|
if(!d)
|
|
ptemp->tn.lval >>= 16;
|
|
ptemp->tn.lval &= 0xffff;
|
|
break;
|
|
} else if (typlen(typ)==1) {
|
|
if(!d)
|
|
ptemp->tn.lval >>= 8;
|
|
ptemp->tn.lval &= 0xff;
|
|
break;
|
|
}
|
|
}
|
|
case NAME:
|
|
case VAUTO:
|
|
case VPARAM:
|
|
ptemp->tn.lval += d;
|
|
break;
|
|
case STAR:
|
|
p = p->in.left;
|
|
switch( p->in.op )
|
|
{
|
|
case REG:
|
|
/* form ( STAR (PLUS REG ICON(4) ) */
|
|
l = ptemp->in.left = talloc();
|
|
*l = *p; /* copy type and other info */
|
|
l->tn.op = PLUS;
|
|
l->in.left = talloc(); /* copy REG node */
|
|
*(l->in.left ) = *p; /* copy REG node */
|
|
r = l->in.right = talloc(); /* node for icon */
|
|
*r = *p; /* copy type and other info */
|
|
r->tn.op = ICON;
|
|
r->tn.lval = d;
|
|
break;
|
|
|
|
case MINUS:
|
|
if (p->in.right->in.op != ICON)
|
|
goto bad;
|
|
d = -d;
|
|
/* FALL THRU */
|
|
case PLUS:
|
|
if (p->in.right->in.op == ICON)
|
|
{
|
|
/* Make copy of address tree with ICON */
|
|
/* modified by adding d */
|
|
l = ptemp->in.left = talloc();
|
|
*l = *p; /* copy PLUS node */
|
|
r = l->in.right = talloc();
|
|
*r= *(p->in.right); /* copy ICON node */
|
|
if ( r->in.op != ICON ) goto bad;
|
|
r->tn.lval += d;
|
|
l->in.left = talloc();
|
|
l = l->in.left;
|
|
p = p->in.left;
|
|
*l = *p; /* make copy of either REG or REG+REG */
|
|
if( l->in.op == REG ) break; /* Done with copy */
|
|
if( l->in.op != PLUS) goto bad; /* Bad address tree */
|
|
l->in.right=talloc(); /* Copy REG */
|
|
*(l->in.right) = *(p->in.right); /* Copy REG */
|
|
l->in.left = talloc();
|
|
l = l->in.left;
|
|
p = p->in.left;
|
|
*l = *p; /* Copy REG or CONV */
|
|
if( l->in.op == REG ) break; /* Done with copy */
|
|
if( l->in.op != CONV) goto bad; /* Bad address tree */
|
|
l->in.left=talloc(); /* Copy REG */
|
|
*(l->in.left) = *(p->in.left); /* Copy REG */
|
|
break;
|
|
|
|
}
|
|
else if (p->in.right->in.op == REG)
|
|
{
|
|
/* Make copy of address tree with ICON */
|
|
/* adding d */
|
|
l = ptemp->in.left = talloc();
|
|
*l = *p; /* copy PLUS node */
|
|
r = l->in.right = talloc();
|
|
*r = *p;
|
|
r->tn.op = ICON;
|
|
r->tn.lval = d;
|
|
l->in.left = talloc();
|
|
l = l->in.left;
|
|
*l = *p; /* copy PLUS node */
|
|
r = l->in.right = talloc();
|
|
*r= *(p->in.right); /* copy REG node */
|
|
l->in.left = talloc();
|
|
*(l->in.left) = *(p->in.left); /* make copy of REG */
|
|
break;
|
|
}
|
|
|
|
default: goto bad;
|
|
};
|
|
break;
|
|
default:
|
|
goto bad;
|
|
} /* switch */
|
|
|
|
if(flg)
|
|
nadrput(ptemp);
|
|
else
|
|
adrput( ptemp );
|
|
tfree( ptemp );
|
|
}
|
|
else {
|
|
if(flg)
|
|
nadrput(p);
|
|
else
|
|
adrput(p);
|
|
}
|
|
return;
|
|
bad:
|
|
e2print( ptemp );
|
|
cerror("Illegal byte address (ZB)\n");
|
|
return(-1);
|
|
}
|
|
|
|
zzzcode( p, ppc , q)
|
|
register NODE *p;
|
|
register char **ppc;
|
|
OPTAB *q;
|
|
{
|
|
register int c;
|
|
register int ii;
|
|
register NODE *newp, *tnode;
|
|
register int displ,t;
|
|
TWORD ht;
|
|
|
|
static int labels[10]; /* labels for use in patterns */
|
|
|
|
switch( c= *++(*ppc) )
|
|
{
|
|
/*
|
|
case 'p':
|
|
popargs( 4 );
|
|
return;
|
|
case 'q':
|
|
popargs( 8 );
|
|
return;
|
|
*/
|
|
case 'c':
|
|
popargs((short)(p->stn.argsize/SZCHAR));
|
|
return;
|
|
/*
|
|
case '1':
|
|
if( toff )
|
|
{
|
|
putchar( '-' );
|
|
}
|
|
printf( "(%%sp)" );
|
|
if( !toff ) toffbase = 1;
|
|
++toff;
|
|
return;
|
|
|
|
case '2':
|
|
if( toff )
|
|
{
|
|
putchar( '-' );
|
|
}
|
|
printf( "(%%sp)" );
|
|
if( !toff ) toffbase = 2;
|
|
toff+=2;
|
|
return;
|
|
|
|
case '0':
|
|
/* like 2 but doesn't print -(%%sp) */
|
|
/* used for pea. leaves toffbase at 0, also */
|
|
/* toff += 2;
|
|
return;
|
|
*/
|
|
case 's': /* like s, but needs value afterwards */
|
|
case 'S': /* structure assignment */
|
|
if( p->in.op == STASG )
|
|
{
|
|
stas( p, p->stn.stsize, c);
|
|
}
|
|
else if( p->in.op == STARG )
|
|
{
|
|
/* store an arg onto the stack */
|
|
star( p->in.left, p->stn.stsize ,q);
|
|
}
|
|
else
|
|
{
|
|
e2print(p);
|
|
cerror( "ZS bad" );
|
|
}
|
|
break;
|
|
|
|
case 'z': /* adjust register on right */
|
|
{
|
|
register long adj = p->stn.stsize;
|
|
if( adj == SZSHORT || adj == SZLONG ) return;
|
|
adj /= SZCHAR;
|
|
if( adj > 16)
|
|
printf( "\tsub\t%s,#%%%x\n",
|
|
prnames(TINT, p->in.right->tn.rval+1, 0), (unsigned short)adj);
|
|
else if( adj)
|
|
printf( "\tdec\t%s,#%%%x\n",
|
|
prnames(TINT, p->in.right->tn.rval+1,0), adj);
|
|
}
|
|
return;
|
|
|
|
case 'I':
|
|
cbgen( p->bn.lop, (int)(p->bn.label), c );
|
|
return;
|
|
|
|
case 'i':
|
|
++*ppc;
|
|
p = getadr(p,ppc);
|
|
printf("%s",prnames(TINT,p->tn.rval,0));
|
|
|
|
/* c = p->in.left->in.left->tn.rval; /* register number */
|
|
/* dbccgen( p->bn.lop, p->bn.label, c );*/
|
|
return;
|
|
|
|
case 'b':
|
|
++*ppc;
|
|
p = getadr(p,ppc);
|
|
if((ii = ispow2(p->tn.lval))>=0)
|
|
{
|
|
printf( "#%%%x", ii );
|
|
break;
|
|
}
|
|
cerror( "Zb but not power of 2" );
|
|
|
|
case 'n':
|
|
/* ++*ppc;
|
|
next_address( getadr(p,ppc), 4 );
|
|
*/
|
|
displ = ((*++(*ppc)) - '0');
|
|
if(!displ) displ += NFLG; /* da 'B' auch next_address nutzt */
|
|
switch(*++(*ppc)) {
|
|
case 'c': t = TCHAR; break;
|
|
case 's': t = TINT; break;
|
|
case 'l': t = TLONG; break;
|
|
case 'd': t = TDOUBLE; break;
|
|
}
|
|
++*ppc;
|
|
ii = 0;
|
|
if(**ppc == 'B') {
|
|
**ppc = 'A';
|
|
ii = 1;
|
|
}
|
|
next_address( getadr(p,ppc), displ, t , ii);
|
|
break;
|
|
|
|
case 'y': /* CONV reg to shorter reg */
|
|
/* CONV for regvar in char only in scatchregs */
|
|
{ char qt,zt;
|
|
qt = *++(*ppc);
|
|
zt = *++(*ppc);
|
|
++*ppc;
|
|
tnode = getadr(p,ppc);
|
|
if(zt == 'c') {
|
|
++*ppc;
|
|
newp = getadr(p,ppc);
|
|
if(newp->tn.type&TCHAR)
|
|
newp->tn.type=(~TCHAR&newp->tn.type)|
|
|
TSHORT;
|
|
else
|
|
if(newp->tn.type&TUCHAR)
|
|
newp->tn.type=(~TUCHAR&newp->tn.type)|
|
|
TUSHORT;
|
|
else cerror(" bad 'CONV' registertype ");
|
|
ht = newp->tn.type;
|
|
if((tnode->tn.rval & 0xf) > 7 ) {
|
|
printf("\tld\t");
|
|
adrput(newp);
|
|
putchar(',');
|
|
if(qt == 'l') {
|
|
tnode->tn.rval++;
|
|
tnode->tn.type = TINT;
|
|
}
|
|
adrput(tnode);
|
|
putchar('\n');
|
|
}
|
|
else {
|
|
*newp = *tnode;
|
|
if(qt == 'l') {
|
|
newp->tn.rval++;
|
|
}
|
|
newp->tn.type = ht;
|
|
newp->bn.label = 1;
|
|
}
|
|
}
|
|
if(zt == 's') {
|
|
if(tnode->tn.type&TLONG)
|
|
tnode->tn.type=(~TLONG&tnode->tn.type)|
|
|
TSHORT;
|
|
else
|
|
if(tnode->tn.type&TULONG)
|
|
tnode->tn.type=(~TULONG&tnode->tn.type)|
|
|
TUSHORT;
|
|
else
|
|
if(tnode->tn.type&TPOINT)
|
|
tnode->tn.type =
|
|
((~TPOINT & tnode->tn.type) & ~BTMASK)|
|
|
TSHORT;
|
|
else cerror(" bad 'CONV' registertype ");
|
|
rfree(tnode->tn.rval,1);
|
|
tnode->tn.rval++;
|
|
tnode->bn.label = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case 'f': /* shift by number of lowest bit on */
|
|
++*ppc;
|
|
newp = getadr(p, ppc);
|
|
c = newp->tn.lval;
|
|
if (c > 0)
|
|
{
|
|
for (ii = 0; (c & 1) == 0; ii++)
|
|
c >>= 1;
|
|
doshift(ii, ppc, p);
|
|
}
|
|
else
|
|
cerror( "Zf on zero or negative value" );
|
|
break;
|
|
|
|
case 'd': /* shift by diff. of powers of 2 (for sums of powers) */
|
|
++*ppc;
|
|
newp = getadr(p, ppc);
|
|
c = newp->tn.lval;
|
|
if (c > 0)
|
|
{
|
|
while ((c & 1) == 0)
|
|
c >>= 1;
|
|
if ((c >>= 1) != 0 && (c & (c-1)) == 0) /* 1 bit left */
|
|
{
|
|
for (ii = 1; (c & 1) == 0; ii++)
|
|
c >>= 1;
|
|
doshift(ii, ppc, p);
|
|
break;
|
|
}
|
|
}
|
|
cerror( "Zd on improper value" );
|
|
break;
|
|
|
|
case 'D': /* shift by diff. of powers of 2 (for diff.) */
|
|
++*ppc;
|
|
newp = getadr(p, ppc);
|
|
c = newp->tn.lval;
|
|
if (c > 0)
|
|
{
|
|
while ((c & 1) == 0) /* get to '00...011...1' */
|
|
c >>= 1;
|
|
if (c != 0 && (c & (c+1)) == 0) /* string of 1's */
|
|
{
|
|
for (ii = 0; (c & 1); ii++) /* count 1's */
|
|
c >>= 1;
|
|
doshift(ii, ppc, p);
|
|
break;
|
|
}
|
|
}
|
|
cerror( "ZD on improper value" );
|
|
break;
|
|
|
|
case 'B': /* byte address for a bset, bclr */
|
|
++*ppc;
|
|
newp = getadr(p, ppc);
|
|
if((ii = ispow2(newp->tn.lval)) < 0)
|
|
{
|
|
cerror( "ZB but not power of 2" );
|
|
return;
|
|
}
|
|
if(typlen(newp->tn.type)==1)
|
|
ii&=7;
|
|
printf("#%%%x", ii); /* output the bit number (mod 8) */
|
|
break;
|
|
|
|
case 't': /* take address of temp */
|
|
++*ppc;
|
|
newp = getadr(p, ppc); /* the temp */
|
|
++*ppc;
|
|
p = getadr(p, ppc); /* the result reg */
|
|
if (newp->tn.rval == 0) /* memory temp? */
|
|
{
|
|
printf("\tldl\t");
|
|
adrput(p);
|
|
printf(",FP\n\tadd\t");
|
|
next_address(p, 2, TINT, 0);
|
|
printf(",#%%%x\n", (unsigned short)(2+(int)newp->tn.lval));
|
|
break;
|
|
}
|
|
tnode = talloc(); /* the memory temp */
|
|
*tnode = *newp; /* copy stuff */
|
|
tnode->tn.lval = freetemp((OFFSZ)1); /* get a memory temp */
|
|
tnode->tn.lval = BITOOR(tnode->tn.lval);
|
|
tnode->tn.rval = 0; /* not in register */
|
|
if( typlen(tnode->tn.type) >= 4)
|
|
c = 'l'; /* move long */
|
|
else if(typlen(tnode->tn.type)==2)
|
|
c = ' '; /* move word */
|
|
else
|
|
c = 'b'; /* move byte */
|
|
printf("\tld%c\t", c);
|
|
adrput(tnode);
|
|
putchar(',');
|
|
adrput( newp );
|
|
if(typlen(tnode->tn.type) == 8) {
|
|
printf("\tldl\t");
|
|
next_address(tnode, 4, TLONG, 0);
|
|
putchar(',');
|
|
next_address(newp, 4, TLONG, 0);
|
|
}
|
|
printf("\tldl\t");
|
|
adrput(p);
|
|
printf(",FP\n\tadd\t");
|
|
next_address(p, 2, TINT, 0);
|
|
printf(",#%%%x\n", (unsigned short)(2+(int)tnode->tn.lval));
|
|
tfree( tnode );
|
|
break;
|
|
|
|
case 'L': /* first use of label in pattern */
|
|
case 'l': /* other uses of label in pattern */
|
|
ii = *++(*ppc) - '0'; /* label number */
|
|
if (ii < 0 || ii > 9)
|
|
cerror( "illegal %c code: %c", c, ii+'0');
|
|
if (c == 'L') /* define it */
|
|
labels[ii] = getlab();
|
|
printf("L%d", labels[ii]);
|
|
break;
|
|
|
|
default:
|
|
e2print(p);
|
|
cerror( "illegal zzzcode: %c", c );
|
|
}
|
|
}
|
|
|
|
/* put a shift left of size s of register A? from string "sA?" */
|
|
doshift (n, ppc, p)
|
|
register int n;
|
|
register char **ppc;
|
|
register NODE *p;
|
|
{
|
|
register char size;
|
|
register unsflg = 0;
|
|
|
|
size= *++(*ppc);
|
|
if(size == 'u') {
|
|
size = *++(*ppc);
|
|
unsflg++;
|
|
}
|
|
|
|
if(size == 's')
|
|
size = ' ';
|
|
++*ppc;
|
|
p = getadr(p, ppc);
|
|
if (n == 1)
|
|
{
|
|
printf("\tadd%c\t", size);
|
|
adrput(p);
|
|
putchar(',');
|
|
adrput(p);
|
|
putchar('\n');
|
|
}
|
|
else if (n > 1)
|
|
{
|
|
if(unsflg)
|
|
printf("\tsll%c\t",size);
|
|
else
|
|
printf("\tsla%c\t",size);
|
|
adrput(p);
|
|
printf(",#%%%x\n", n);
|
|
/*
|
|
putchar('\n');
|
|
*/
|
|
}
|
|
/* null for shift of 0 */
|
|
}
|
|
|
|
star( p, sz , q)
|
|
register NODE *p;
|
|
OFFSZ sz;
|
|
OPTAB *q;
|
|
{
|
|
/* put argument onto the stack */
|
|
/* p is a REG */
|
|
|
|
if( p->tn.op != REG ) uerror( "star of non-REG" );
|
|
/*
|
|
sz /= (SZCHAR << 1);
|
|
*/
|
|
sz /= SZCHAR;
|
|
|
|
/*
|
|
if(sz > 2) {
|
|
*/
|
|
if(sz > 4) { /* mit ldir */
|
|
char rn[4];
|
|
char *dec = "dec";
|
|
if(sz > 16)
|
|
dec = "sub";
|
|
strcpy(rn, prnames(TINT, resc[0].tn.rval,0));
|
|
printf("\tld\t%s,#%%%x\n",rn,(unsigned short)sz);
|
|
printf("\tsub\tsp,%s\n",rn);
|
|
printf("\tld\t@SP,#0\n\tldirb\t@SP,@%s,%s\n",
|
|
prnames(TLONG,p->tn.rval,0) ,rn);
|
|
printf("\t%s\tsp,#%%%x\n",dec,(unsigned short)sz);
|
|
} else
|
|
printf("\tpush%c\t@SP,%s\n",((sz==4)?'l':' '),
|
|
prnames((sz==4)?TLONG:TINT, p->tn.rval,0));
|
|
|
|
}
|
|
|
|
stas( p, sz, c )
|
|
register NODE *p;
|
|
OFFSZ sz;
|
|
register c;
|
|
{
|
|
/* p is an STASG node; left and right are regs */
|
|
/* all structures are aligned on int boundaries */
|
|
|
|
register rn, ln, zz, scn;
|
|
|
|
rn = p->in.right->tn.rval;
|
|
if( c == 's' )
|
|
{
|
|
/* lhs is a temp moved into a reg: kluge! */
|
|
ln = resc[0].tn.rval; /* A1 */
|
|
scn = resc[1].tn.rval; /* A2 */
|
|
}
|
|
else {
|
|
ln = p->in.left->tn.rval;
|
|
scn = resc[0].tn.rval; /* A1 */
|
|
}
|
|
|
|
zz = (sz /= SZCHAR) >> 1;
|
|
if(zz > 2) {
|
|
char * dec = "dec";
|
|
if(zz > 8)
|
|
dec = "sub";
|
|
printf("\tld\t%s,#%%%x\n",prnames(TINT, scn,0), (unsigned short)zz);
|
|
printf("\tldir\t@%s,",prnames(TLONG,ln,0));
|
|
printf("@%s,",prnames(TLONG,rn,0));
|
|
printf("%s\n",prnames(TINT,scn,0));
|
|
if( (ln & 0xf) > 7) /* regvar */
|
|
/* restore clobbered register variable */
|
|
printf( "\t%s\t%s,#%%%x\n",dec,
|
|
prnames(TINT, ln+1,0), (unsigned short)sz);
|
|
if( (rn & 0xf) > 7) /* regvar */
|
|
/* restore clobbered register variable */
|
|
printf( "\t%s\t%s,#%%%x\n",dec,
|
|
prnames(TINT, rn+1,0), (unsigned short)sz);
|
|
} else if(zz == 2) {
|
|
printf("\tldl\trx0,@r%s\n",prnames(TLONG, rn,0));
|
|
printf("\tldl\t@r%s,rx0\n",prnames(TLONG, ln,0));
|
|
} else if (zz == 1) {
|
|
printf("\tld\tx0,@r%s\n",prnames(TINT, rn,0));
|
|
printf("\tld\t@r%s,x0\n",prnames(TINT, ln,0));
|
|
} else {
|
|
e2print(p);
|
|
cerror( "ZS sz %ld", sz );
|
|
}
|
|
}
|
|
|
|
conput( p )
|
|
register NODE *p;
|
|
{
|
|
char *s;
|
|
int typ;
|
|
switch( p->in.op )
|
|
{
|
|
case ICON:
|
|
acon( p );
|
|
return;
|
|
case REG:
|
|
printf("%s", prnames(p->tn.type, p->tn.rval,p->bn.label));
|
|
return;
|
|
default:
|
|
e2print(p);
|
|
cerror( "illegal conput" );
|
|
}
|
|
}
|
|
|
|
insput( p )
|
|
NODE *p;
|
|
{
|
|
e2print(p);
|
|
cerror( "insput" );
|
|
}
|
|
|
|
#ifdef UPPUT
|
|
|
|
upput( pp )
|
|
register NODE *pp;
|
|
{
|
|
/* output the address of the second word in the
|
|
** pair pointed to by p (for LONGs)
|
|
*/
|
|
register long v;
|
|
register NODE *r, *l, *p;
|
|
|
|
v=0;
|
|
p = pp;
|
|
if( p->tn.op == PLUS )
|
|
{
|
|
/*
|
|
v=0;
|
|
r = p->in.right;
|
|
l = p->in.left;
|
|
if( r->tn.op == ICON && l->tn.op == PLUS )
|
|
{
|
|
v = r->tn.lval;
|
|
p = l;
|
|
r = p->in.right;
|
|
l = p->in.left;
|
|
}
|
|
if( r->tn.op == REG )
|
|
{
|
|
l = p->in.left;
|
|
if( l->tn.op == REG )
|
|
{
|
|
printf( "%%%lx(%%a%d,%%d%d.l)", v, r->tn.rval,
|
|
l->tn.rval );
|
|
return;
|
|
}
|
|
if( l->tn.op != CONV ) goto ill;
|
|
l = l->in.left;
|
|
if( l->tn.op != REG ) goto ill;
|
|
printf("%%%lx(%%a%d,%%d%d.w)",v,r->tn.rval,l->tn.rval);
|
|
return;
|
|
}
|
|
not by Z8000 */
|
|
if( r->tn.op != ICON ) goto ill;
|
|
v = r->tn.lval;
|
|
p = p->in.left;
|
|
}
|
|
else if( p->tn.op == MINUS )
|
|
{
|
|
r = p->in.right;
|
|
if( r->tn.op != ICON || r->in.name != (char *) 0 ) goto ill;
|
|
v = -r->tn.lval;
|
|
p = p->in.left;
|
|
}
|
|
if( p->tn.op != REG ) goto ill;
|
|
if( v )
|
|
/*
|
|
printf( "%%%lx(%%a%s)", v, rnames[p->tn.rval] );
|
|
else
|
|
printf( "(%%a%s)", rnames[p->tn.rval] );
|
|
*/
|
|
printf( "_stkseg+%%%x(%s)",(unsigned short) v, prnames(TLONG,p->tn.rval,0) );
|
|
else
|
|
printf( "@%s", prnames(TLONG,p->tn.rval,0) );
|
|
return;
|
|
ill:
|
|
e2print(pp);
|
|
cerror( "illegal address: upput" );
|
|
}
|
|
|
|
#else
|
|
upput( pp )
|
|
register NODE *pp;
|
|
{
|
|
/* output the address of the second word in the
|
|
** pair pointed to by p (for LONGs)
|
|
*/
|
|
if( pp->tn.op == REG ) {
|
|
printf( "@%s", prnames(TLONG,pp->tn.rval,0) );
|
|
return;
|
|
}
|
|
e2print(pp);
|
|
cerror( "illegal address: upput" );
|
|
}
|
|
#endif UPPUT
|
|
|
|
adrput( p )
|
|
register NODE *p;
|
|
{
|
|
/* output an address, with offsets, from p */
|
|
|
|
while( p->in.op == FLD || p->in.op == CONV )
|
|
{
|
|
p = p->in.left;
|
|
}
|
|
switch( p->in.op )
|
|
{
|
|
|
|
case NAME:
|
|
acon( p );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case ICON:
|
|
/* addressable value of the constant */
|
|
printf( "#" );
|
|
acon( p );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case REG:
|
|
conput( p );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case STAR:
|
|
upput( p->in.left );
|
|
return;
|
|
|
|
case VAUTO:
|
|
if ((int)p->tn.lval < 0)
|
|
printf( "_stkseg+~L1-%%%x(fp)", (unsigned short)(-(p->tn.lval)) );
|
|
else
|
|
printf( "_stkseg+~L1+%%%x(fp)", (unsigned short) (p->tn.lval) );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case VPARAM:
|
|
if ((int)p->tn.lval < 0)
|
|
printf( "_stkseg+~L2-%%%x(fp)", (unsigned short)(-(p->tn.lval)) );
|
|
else
|
|
printf( "_stkseg+~L2+%%%x(fp)", (unsigned short) p->tn.lval );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case TEMP:
|
|
if (p->tn.rval)
|
|
{
|
|
register int i = (int)p->tn.lval;
|
|
|
|
printf("%s", prnames(p->tn.type, i, 0));
|
|
}
|
|
else
|
|
printf( "_stkseg+%%%x(fp)", (unsigned short)(2 + p->tn.lval));
|
|
sideff = 0;
|
|
return;
|
|
|
|
default:
|
|
e2print(p);
|
|
cerror( "illegal address" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* lda ala OF */
|
|
padrput( p )
|
|
register NODE *p;
|
|
{
|
|
/* output an address, with offsets, from p */
|
|
|
|
switch( p->in.op )
|
|
{
|
|
|
|
case VAUTO:
|
|
/* offset only !!! without FP */
|
|
if ((int)p->tn.lval < 0)
|
|
printf( "#~L1-%%%x", (unsigned short)(-(p->tn.lval)) );
|
|
else
|
|
printf( "#~L1+%%%x", (unsigned short)(p->tn.lval) );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case VPARAM:
|
|
/* offset only !!! without FP */
|
|
if ((int)p->tn.lval < 0)
|
|
printf( "#~L2-%%%x", (unsigned short)(-(p->tn.lval)) );
|
|
else
|
|
printf( "#~L2+%%%x", (unsigned short)(p->tn.lval) );
|
|
sideff = 0;
|
|
return;
|
|
|
|
default:
|
|
e2print(p);
|
|
cerror( "illegal address" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* for BA-addressing in ld-Operations */
|
|
nadrput( p )
|
|
register NODE *p;
|
|
{
|
|
/* output an address, with offsets, from p */
|
|
|
|
switch( p->in.op )
|
|
{
|
|
|
|
case VAUTO:
|
|
if ((int)p->tn.lval < 0)
|
|
printf( "FP(#~L1-%%%x)", (unsigned short)(-(p->tn.lval)) );
|
|
else
|
|
printf( "FP(#~L1+%%%x)", (unsigned short) (p->tn.lval) );
|
|
sideff = 0;
|
|
return;
|
|
|
|
case VPARAM:
|
|
if ((int)p->tn.lval < 0)
|
|
printf( "FP(#~L2-%%%x)", (unsigned short)(-(p->tn.lval)) );
|
|
else
|
|
printf( "FP(#~L2+%%%x)", (unsigned short) p->tn.lval );
|
|
sideff = 0;
|
|
return;
|
|
|
|
}
|
|
adrput( p );
|
|
}
|
|
|
|
acon( p )
|
|
register NODE *p;
|
|
{
|
|
/* print out a constant */
|
|
|
|
if( p->in.name != (char *) 0) {
|
|
/* names */
|
|
switch(p->tn.rval) {
|
|
case 0x1000:
|
|
printf("^s _%s", p->in.name );
|
|
return;
|
|
case 0x2000:
|
|
printf("^o _");
|
|
break;
|
|
case 0x9000:
|
|
printf("^s %s", p->in.name );
|
|
return;
|
|
case 0xa000:
|
|
printf("^o ");
|
|
break;
|
|
case 0x3000:
|
|
printf("_%s(",p->in.name);
|
|
prnames(TINT,(int)p->tn.lval,0);
|
|
putchar(')');
|
|
return;
|
|
default:
|
|
if(p->tn.rval >= 0 || *(p->in.name)!='L')
|
|
putchar('_');
|
|
}
|
|
printf("%s", p->in.name );
|
|
if(p->tn.lval)
|
|
putchar('+');
|
|
else
|
|
return;
|
|
} else if(typlen(p->tn.type) >= 4 ) {
|
|
printf( "%%%lx", p->tn.lval);
|
|
return;
|
|
}
|
|
printf( "%%%x", (unsigned short)p->tn.lval);
|
|
}
|
|
|
|
/* alte version
|
|
acon( p )
|
|
register NODE *p;
|
|
{
|
|
if( p->in.name == (char *) 0)
|
|
{
|
|
if(typlen(p->tn.type) < 4)
|
|
printf( "%%%x", (unsigned short) p->tn.lval);
|
|
else
|
|
printf( "%%%lx", p->tn.lval);
|
|
} else if( p->tn.rval == 0x2000 ) {
|
|
printf("^o _%s",p->in.name);
|
|
} else if( p->tn.rval == 0x1000 ) {
|
|
printf( "^s _%s", p->in.name );
|
|
} else if( p->tn.rval == 0xa000 ) {
|
|
printf("^o %s",p->in.name);
|
|
} else if( p->tn.rval == 0x9000 ) {
|
|
printf( "^s %s", p->in.name );
|
|
} else if( p->tn.rval == 0x3000 ) {
|
|
printf("_%s(",p->in.name);
|
|
prnames(TINT,(int)p->tn.lval,0);
|
|
putchar(')');
|
|
} else if( p->tn.lval == 0 ) {
|
|
if(p->tn.rval < 0 && *(p->in.name)=='L')
|
|
printf("%s",p->in.name);
|
|
else
|
|
printf( "_%s", p->in.name );
|
|
}
|
|
else
|
|
{
|
|
if(p->tn.rval < 0 && *(p->in.name)=='L')
|
|
printf( "%s+%%%x", p->in.name , (unsigned short) p->tn.lval );
|
|
else
|
|
printf( "_%s+%%%x", p->in.name , (unsigned short) p->tn.lval );
|
|
}
|
|
if( p->tn.lval != 0 && (p->tn.rval == 0xa000 || p->tn.rval == 0x2000))
|
|
printf( "+%%%x", (unsigned short) p->tn.lval );
|
|
}
|
|
*/
|
|
static char *ccbranches[] =
|
|
{
|
|
/*
|
|
" beq L%%%d\n",
|
|
" bne L%%%d\n",
|
|
" ble L%%%d\n",
|
|
" blt L%%%d\n",
|
|
" bge L%%%d\n",
|
|
" bgt L%%%d\n",
|
|
" bls L%%%d\n",
|
|
" blo L%%%d\n",
|
|
" bhs L%%%d\n",
|
|
" bhi L%%%d\n",
|
|
*/
|
|
" jpr eq,L%d\n",
|
|
" jpr ne,L%d\n",
|
|
" jpr le,L%d\n",
|
|
" jpr lt,L%d\n",
|
|
" jpr ge,L%d\n",
|
|
" jpr gt,L%d\n",
|
|
" jpr ule,L%d\n",
|
|
" jpr ult,L%d\n",
|
|
" jpr uge,L%d\n",
|
|
" jpr ugt,L%d\n",
|
|
};
|
|
|
|
cbgen( o, lab, mode )
|
|
register o,lab;
|
|
{
|
|
/* printf conditional and unconditional branches */
|
|
if( o == 0 ) printf( " jpr L%d\n", lab );
|
|
else if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
|
|
else printf( ccbranches[o-EQ], lab );
|
|
}
|
|
|
|
static char *dbccops[] =
|
|
{
|
|
/*
|
|
" dbeq %%d%d,L%%%d\n",
|
|
" dbne %%d%d,L%%%d\n",
|
|
" dble %%d%d,L%%%d\n",
|
|
" dblt %%d%d,L%%%d\n",
|
|
" dbge %%d%d,L%%%d\n",
|
|
" dbgt %%d%d,L%%%d\n",
|
|
" dbls %%d%d,L%%%d\n",
|
|
" dblo %%d%d,L%%%d\n",
|
|
" dbhs %%d%d,L%%%d\n",
|
|
" dbhi %%d%d,L%%%d\n",
|
|
*/
|
|
"ne", "eq", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule",
|
|
};
|
|
|
|
dbccgen( o, lab, reg )
|
|
register o,reg,lab;
|
|
{
|
|
/* printf conditional and unconditional branches */
|
|
int l;
|
|
/*
|
|
if( o == 0 ) printf( " dbt %%d%d,L%%%d\n", reg, lab );
|
|
else if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
|
|
else printf( dbccops[o-EQ], reg, lab );
|
|
*/
|
|
if( o == 0) printf("\tdec\t%s\n\tjpr\tpl,L%d\n",prnames(TINT,reg,0),lab);
|
|
else if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
|
|
else {
|
|
l = getlab();
|
|
printf("\tjr\t%s,L%d\n\tdec\t%s\n\tjpr\tpl,L%d\nL%d:\n",
|
|
dbccops[o-EQ],l,prnames(TINT,reg,0),lab,l);
|
|
}
|
|
}
|
|
|
|
/* see if an unused register can be used for a temp */
|
|
|
|
/*#define DREGS (0xff & (0xff<<NRGS)) /* the available D registers */
|
|
/*#define AREGS (0x3f00 & (0xff00<<NRGS)) /* the available A registers */
|
|
#define MREGS 0xf00 /* 4 available registers 8...11 for scratch */
|
|
|
|
int regtmp = 0;
|
|
|
|
tempreg(rnum, nlongs, type)
|
|
register int *rnum; /* returns regiser number if one allocated */
|
|
OFFSZ nlongs; /* number of long words needed for the temp */
|
|
register TWORD type; /* type of the value to be put in the temp */
|
|
{
|
|
register int r, rbit, mask;
|
|
extern int regvar;
|
|
|
|
if (nlongs != 1 || ((type & TSTRUCT) && !(type & TPOINT)))
|
|
return (0); /* can't have > 1 reg or structures */
|
|
mask = ~(regvar | regtmp); /* consider all unallocated registers */
|
|
|
|
/* if ((type & TPOINT) && (mask & AREGS)) */
|
|
/* mask &= AREGS; /* prefer pointers in A registers */
|
|
/* /* but can be put in D registers if no A's */
|
|
/* else */
|
|
/* mask &= DREGS; /* non-pointers restricted to D registers */
|
|
mask &= MREGS;
|
|
|
|
if (mask == 0)
|
|
return(0); /* none available! */
|
|
|
|
for (r = 8, rbit = 0x100; (mask & rbit) == 0; r++)
|
|
rbit <<= 1;
|
|
/* mark it used */
|
|
regtmp |= rbit;
|
|
SETREGS(rbit);
|
|
*rnum = r;
|
|
return (1); /* success! */
|
|
}
|