Latest version from Albert Koelmans
This commit is contained in:
parent
8a00e32bc8
commit
33dc73d4c4
6 changed files with 394 additions and 132 deletions
|
@ -1,12 +1,13 @@
|
|||
/* $Header; mach0.c, v1.1 20-Oct-88 AJM */
|
||||
/* $Header; mach0.c, v1.2 06-Mar-89 AJM */
|
||||
|
||||
#define LISTING
|
||||
#define ASLD
|
||||
#define THREE_PASS
|
||||
|
||||
#define DEBUG 0
|
||||
/*
|
||||
#define WORDS_REVERSED
|
||||
#define BYTES_REVERSED
|
||||
|
||||
*/
|
||||
#undef valu_t
|
||||
#define valu_t long
|
||||
|
||||
|
@ -44,4 +45,6 @@
|
|||
#define CMP 0x01500000
|
||||
#define TEQ 0x01300000
|
||||
#define TST 0x01100000
|
||||
#define LDR 0x04100000
|
||||
#define STR 0x04000000
|
||||
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
/* $Header; mach1.c, v1.1 06-Mar-89 AJM */
|
||||
extern word_t opcode;
|
||||
extern int success; /* LDR/STR address failure flag */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Header: mach2.c, V1.3 2-Nov-88 AJM */
|
||||
/* $Header: mach2.c, V1.4 15-Mar-89 AJM */
|
||||
%token <y_word> COND
|
||||
%token <y_word> LINK
|
||||
%token <y_word> BRANCH
|
||||
|
@ -20,5 +20,5 @@
|
|||
%token <y_word> MLA
|
||||
|
||||
%type <y_word> optlink optcond opts optt optp optb optexc reglist rlist
|
||||
%type <y_word> optsign optpsr optshift shftcnt address offset
|
||||
%type <y_word> optsign optpsr optshift shftcnt address offset aoptshift
|
||||
%type <y_expr> operand
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Header: mach3.c, v1.5 2-Nov-88 AJM */
|
||||
/* $Header: mach3.c, v2.0 23-Feb-89 AJM */
|
||||
|
||||
0, COND, 0x00000000, ".EQ",
|
||||
0, COND, 0x10000000, ".NE",
|
||||
|
@ -77,6 +77,7 @@
|
|||
0, REG, 13, "R13",
|
||||
0, REG, 14, "R14",
|
||||
0, REG, 15, "R15",
|
||||
0, REG, 15, "PC",
|
||||
|
||||
0, SHIFT, 0x00000000, "LSL",
|
||||
0, SHIFT, 0x00000000, "ASL",
|
||||
|
@ -97,10 +98,10 @@
|
|||
0, BDT, 0x08100000, "LDMDA",
|
||||
0, BDT, 0x09900000, "LDMIB",
|
||||
0, BDT, 0x08900000, "LDMIA",
|
||||
0, BDT, 0x08100000, "LDMFD",
|
||||
0, BDT, 0x08900000, "LDMFA",
|
||||
0, BDT, 0x09100000, "LDMED",
|
||||
0, BDT, 0x09900000, "LDMEA",
|
||||
0, BDT, 0x08900000, "LDMFD",
|
||||
0, BDT, 0x08100000, "LDMFA",
|
||||
0, BDT, 0x09900000, "LDMED",
|
||||
0, BDT, 0x09100000, "LDMEA",
|
||||
0, BDT, 0x09000000, "STMDB",
|
||||
0, BDT, 0x08000000, "STMDA",
|
||||
0, BDT, 0x09800000, "STMIB",
|
||||
|
@ -112,7 +113,7 @@
|
|||
|
||||
0, SWI, 0x0F000000, "SWI",
|
||||
|
||||
0, ADR, 0, "ADR",
|
||||
0, ADR, 0x00000000, "ADR",
|
||||
|
||||
0, MUL, 0x00000090, "MUL",
|
||||
0, MLA, 0x00200090, "MLA",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Header: mach4.c, v1.5 2-Nov-88 AJM */
|
||||
/* $Header: mach4.c, v1.9 15-Mar-89 AJM */
|
||||
|
||||
operation : BRANCH optlink expr
|
||||
{branch($1, $2, $3.val);}
|
||||
|
@ -9,13 +9,13 @@ operation : BRANCH optlink expr
|
|||
| DATA3 optcond opts optp REG ',' operand
|
||||
{data($1,$2|$3|$4|$5<<16,$7.val,$7.typ);}
|
||||
| SDT optcond optb optt REG ',' address
|
||||
{emit4($1|$2|$3|$4|$5<<12|$7);}
|
||||
{strldr($1,$2|$3|$4|$5<<12,$7);}
|
||||
| BDT optcond REG optexc ',' reglist optpsr
|
||||
{emit4($1|$2|$3<<16|$4|$6|$7);}
|
||||
| SWI optcond expr
|
||||
{emit4($1|$2|$3.val);}
|
||||
| ADR optcond REG ',' expr
|
||||
{calcadr($2, $3, $5.val, $5.typ);}
|
||||
{calcadr($2,$3,$5.val,$5.typ);}
|
||||
| MUL optcond REG ',' REG ',' REG
|
||||
{emit4($1|$2|$3<<16|$5|$7<<8);}
|
||||
| MLA optcond REG ',' REG ',' REG ',' REG
|
||||
|
@ -76,6 +76,14 @@ optshift : ',' SHIFT shftcnt
|
|||
{$$ = 0;}
|
||||
;
|
||||
|
||||
aoptshift : ',' SHIFT '#' expr
|
||||
{$$ = $2|calcshft($4.val, $4.typ, $<y_word>0);}
|
||||
| ',' RRX
|
||||
{$$ = $2;}
|
||||
|
|
||||
{$$ = 0;}
|
||||
;
|
||||
|
||||
shftcnt : '#' expr
|
||||
{$$ = calcshft($2.val, $2.typ, $<y_word>0);}
|
||||
| REG
|
||||
|
@ -83,18 +91,18 @@ shftcnt : '#' expr
|
|||
;
|
||||
|
||||
address : expr
|
||||
{$$ = 0x01000000|calcaddress($1.val,$1.typ,$<y_word>-1);}
|
||||
{success = 0; $$ = $1.val;}
|
||||
| '[' REG ']'
|
||||
{$$ = 0x01000000|$2<<16;}
|
||||
{success = 1; $$ = 0x01000000|$2<<16;}
|
||||
| '[' REG ',' offset ']' optexc
|
||||
{$$ = $2<<16|$4|$6|0x01000000;}
|
||||
{success = 1; $$ = $2<<16|$4|$6|0x01000000;}
|
||||
| '[' REG ']' ',' offset
|
||||
{$$ = $2<<16|$5;}
|
||||
{success = 1; $$ = $2<<16|$5;}
|
||||
;
|
||||
|
||||
offset : '#' expr
|
||||
{$$ = calcoffset($2.val);}
|
||||
| optsign REG optshift
|
||||
| optsign REG aoptshift
|
||||
{$$ = 0x02000000|$1|$2|$3;}
|
||||
;
|
||||
|
||||
|
@ -113,4 +121,9 @@ rlist : REG
|
|||
{$$ = 1<<$1;}
|
||||
| rlist ',' REG
|
||||
{$$ = $1|1<<$3;}
|
||||
| REG '-' REG
|
||||
{
|
||||
for ($$ = 0; $1 <= $3; $1++)
|
||||
$$ |= (1<<$1);
|
||||
}
|
||||
;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Header: mach5.c, v1.6 3-Nov-88 AJM */
|
||||
/* $Header: mach5.c, v3.3 25-Apr-89 AJM */
|
||||
|
||||
branch(brtyp, link, val)
|
||||
word_t brtyp;
|
||||
|
@ -7,7 +7,7 @@ valu_t val;
|
|||
{
|
||||
valu_t offset;
|
||||
|
||||
offset = val - DOTVAL - 8;
|
||||
offset = val - DOTVAL - 8; /* Allow for pipeline */
|
||||
if ((offset & 0xFC000000) != 0 && (offset & 0xFC000000) != 0xFC000000){
|
||||
serror("offset out of range");
|
||||
}
|
||||
|
@ -22,16 +22,31 @@ valu_t val;
|
|||
short typ;
|
||||
{
|
||||
valu_t tmpval;
|
||||
int adrflag = 0;
|
||||
|
||||
if (typ == S_REG){
|
||||
if (typ == S_REG){ /* The argument is a register */
|
||||
emit4(opc|ins|val);
|
||||
return;
|
||||
}
|
||||
|
||||
ins |= 0x02000000;
|
||||
/* Do a bit of optimisation here, since the backend might produce instructions
|
||||
of the type MOV R0, R0, #0. We can ignore these. */
|
||||
|
||||
if (((opc == ADD) || (opc == SUB)) && (val == 0)){ /* ADD or SUB 0 ? */
|
||||
if ((ins & 0x000F0000) == ((ins & 0x0000F000) << 4)) /* Same reg ? */
|
||||
return; /* Don't emit anything */
|
||||
}
|
||||
|
||||
/* No optimisation, so carry on ... */
|
||||
|
||||
ins |= 0x02000000; /* The argument is an immediate value */
|
||||
tmpval = val;
|
||||
if (typ == S_ABS){
|
||||
if (opc == 0xff){ /* This is an ADR */
|
||||
adrflag = 1;
|
||||
opc = MOV;
|
||||
}
|
||||
|
||||
if (typ == S_ABS){ /* An absolute value */
|
||||
if (calcimm(&opc, &tmpval, typ)){
|
||||
emit4(opc|ins|tmpval);
|
||||
return;
|
||||
|
@ -39,50 +54,44 @@ short typ;
|
|||
}
|
||||
|
||||
tmpval = val;
|
||||
if (small(calcimm(&opc, &tmpval, typ),12)){
|
||||
if (!adrflag){ /* Don't do this for ADRs */
|
||||
if (oursmall(calcimm(&opc, &tmpval, typ), 12)){
|
||||
emit4(opc|ins|tmpval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (opc == MOV && typ != S_ABS)
|
||||
{
|
||||
if (small((val & 0xF0000000) == 0xF0000000, 8)){
|
||||
emit4(0xE51F0004 | (ins & 0xF000));
|
||||
emit4(val);
|
||||
if (opc == MOV || opc == MVN || opc == ADD || opc == SUB){
|
||||
if (!bflag && pass == PASS_3){ /* Debugging info */
|
||||
/* warning("MOV/ADD extension"); */
|
||||
/* if (dflag)
|
||||
printf("value: %lx\n", val);*/
|
||||
}
|
||||
if (oursmall((val & 0xFFFF0000) == 0, 8)){
|
||||
putaddr(opc, ins, val, 2);
|
||||
return;
|
||||
}
|
||||
if (small(1,4)){
|
||||
emit4(0xE51F0000 | (ins & 0xF000));
|
||||
emit4(0xEA000000);
|
||||
emit4(val);
|
||||
if (oursmall((val & 0xFF000000) == 0, 4)){
|
||||
putaddr(opc, ins, val, 3);
|
||||
return;
|
||||
}
|
||||
DOTVAL += 16;
|
||||
putaddr(opc, ins, val, 4);
|
||||
return;
|
||||
}
|
||||
if (opc == ADD && typ != S_ABS)
|
||||
{
|
||||
if (small((val & 0xF0000000) == 0xF0000000, 4)){
|
||||
emit4(0xE51F0004 | (ins & 0xF000));
|
||||
emit4(val);
|
||||
emit4(0xE2800000 | (ins&0xFF000) | (ins&0xF000)>>12);
|
||||
return;
|
||||
}
|
||||
emit4(0xE51F0000 | (ins & 0xF000));
|
||||
emit4(0xEA000000);
|
||||
emit4(val);
|
||||
emit4(0xE2800000 | (ins&0xFF000) | (ins&0xF000)>>12);
|
||||
return;
|
||||
}
|
||||
/* default: */
|
||||
|
||||
if (pass == PASS_1)
|
||||
DOTVAL += 16;
|
||||
DOTVAL += 16; /* Worst case we can emit */
|
||||
else
|
||||
serror("immediate value out of range");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Calculate an immediate value. This is not as easy as it sounds, because
|
||||
the ARM uses an 8-bit value and 4-bit shift to encode the value into a
|
||||
12-bit field. Unfortunately this means that some numbers may not fit at
|
||||
all. */
|
||||
|
||||
calcimm(opc,val,typ)
|
||||
word_t *opc;
|
||||
valu_t *val;
|
||||
|
@ -90,78 +99,83 @@ short typ;
|
|||
{
|
||||
int i = 0;
|
||||
|
||||
if (typ == S_UND) return 0;
|
||||
if (typ == S_UND)
|
||||
return(0); /* Can't do anything with an undefined label */
|
||||
|
||||
if ((*val & 0xFFFFFF00) == 0) return 1;
|
||||
if ((*val & 0xFFFFFF00) == 0) /* Value is positive, but < 256, */
|
||||
return(1); /* so doesn't need a shift */
|
||||
|
||||
if ((~*val & 0xFFFFFF00) == 0){
|
||||
if (*opc == AND)
|
||||
{
|
||||
if ((~*val & 0xFFFFFF00) == 0){ /* Value is negative, but < 256, */
|
||||
if (*opc == AND) /* so no shift required, only */
|
||||
{ /* inversion */
|
||||
*val = ~*val;
|
||||
*opc = BIC;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
if (*opc == MOV)
|
||||
{
|
||||
*val = ~*val;
|
||||
*opc = MVN;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
if (*opc == ADC)
|
||||
{
|
||||
*val = ~*val;
|
||||
*opc = SBC;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
}
|
||||
if ((-1**val & 0xFFFFFF00) == 0 ){
|
||||
if ((-1**val & 0xFFFFFF00) == 0){ /* Same idea ... */
|
||||
if (*opc == ADD)
|
||||
{
|
||||
*val *= -1;
|
||||
*opc = SUB;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
if (*opc == CMP)
|
||||
{
|
||||
*val *= -1;
|
||||
*opc = CMN;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
do{
|
||||
rotateleft2(&*val);
|
||||
do{ /* Now we need to shift */
|
||||
rotateleft2(&*val); /* Rotate left by two bits */
|
||||
i++;
|
||||
if((*val & 0xFFFFFF00) == 0){
|
||||
*val = *val|i<<8;
|
||||
return 1;
|
||||
if((*val & 0xFFFFFF00) == 0){ /* Got a value < 256 */
|
||||
*val = *val|i<<8; /* OR in the shift */
|
||||
return(1);
|
||||
}
|
||||
if ((~*val & 0xFFFFFF00) == 0){
|
||||
if (*opc == AND)
|
||||
if ((~*val & 0xFFFFFF00) == 0){ /* If negative, carry out */
|
||||
if (*opc == AND) /* inversion as before */
|
||||
{
|
||||
*val = ~*val|i<<8;
|
||||
*opc = BIC;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
if (*opc == MOV)
|
||||
{
|
||||
*val = ~*val|i<<8;
|
||||
*opc = MVN;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
if (*opc == ADC)
|
||||
{
|
||||
*val = ~*val|i<<8;
|
||||
*opc = SBC;
|
||||
return 1;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}while(i<15);
|
||||
|
||||
return 0;
|
||||
return(0); /* Failed if can't encode it after 16 rotates */
|
||||
}
|
||||
|
||||
|
||||
/* Calculate an offset in an address */
|
||||
|
||||
word_t
|
||||
calcoffset(val)
|
||||
valu_t val;
|
||||
|
@ -175,68 +189,150 @@ valu_t val;
|
|||
return(0);
|
||||
}
|
||||
|
||||
word_t
|
||||
calcaddress (val,typ,reg)
|
||||
valu_t val;
|
||||
short typ;
|
||||
word_t reg;
|
||||
{
|
||||
int tmpval;
|
||||
|
||||
if (typ == S_UND){
|
||||
DOTVAL += 8;
|
||||
return 0;
|
||||
/* This routine deals with STR and LDR instructions */
|
||||
|
||||
strldr(opc, ins, val)
|
||||
long opc, ins;
|
||||
valu_t val;
|
||||
{
|
||||
|
||||
long reg, reg2; /* The registers we are using */
|
||||
long tmpval;
|
||||
|
||||
/* If the expression was a register, then just output it and save 24
|
||||
bytes */
|
||||
|
||||
if (success){
|
||||
emit4(opc|ins|val);
|
||||
return;
|
||||
}
|
||||
|
||||
reg = ins & 0x0000F000; /* Extract register from instruction */
|
||||
|
||||
if (opc == LDR){
|
||||
|
||||
tmpval = val - DOTVAL - 8;
|
||||
if(small((tmpval & 0xFFFFF000) == 0, 8))
|
||||
return(val|0x008F0000);
|
||||
if (oursmall((tmpval & 0xFFFFF000) == 0, 16)){ /* If it's +ve */
|
||||
emit4(opc|ins|tmpval|0x018F0000); /* PC rel, up bit */
|
||||
return;
|
||||
}
|
||||
|
||||
tmpval *= -1;
|
||||
if(small((tmpval & 0xFFFFF000) == 0, 8))
|
||||
return(val|0x000F0000);
|
||||
emit4(0xE51F0004 | reg << 12);
|
||||
emit4(val | 0xF0000000);
|
||||
return(reg << 16);
|
||||
if (oursmall((tmpval & 0xFFFFF000) == 0, 16)){ /* If it's -ve */
|
||||
emit4(opc|ins|tmpval|0x010F0000); /* PC rel, no up bit */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bflag && pass == PASS_3){ /* Debugging info */
|
||||
/* warning("LDR address extension"); */
|
||||
if (dflag)
|
||||
printf("value: %lx\n", val);
|
||||
}
|
||||
|
||||
opc = 0x03A00000; /* Set opc for putaddr */
|
||||
|
||||
if (oursmall((val & 0xFFFF0000) == 0, 8)){
|
||||
putaddr(opc, ins & 0xFFBFFFFF, val, 2);
|
||||
emit4(0x05100000|ins|reg<<4);
|
||||
return;
|
||||
}
|
||||
if (oursmall((val & 0xFF000000) == 0, 4)){
|
||||
putaddr(opc, ins & 0xFFBFFFFF, val, 3);
|
||||
emit4(0x05100000|ins|reg<<4);
|
||||
return;
|
||||
}
|
||||
putaddr(opc, ins & 0xFFBFFFFF, val, 4);
|
||||
emit4(0x05100000|ins|reg<<4);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the failure was an STR instruction, things are a bit more complicated as
|
||||
we can't overwrite the register before we store its value. We therefore
|
||||
need to use another register as well, which must be saved and restored.
|
||||
This register is saved on a stack pointed to by R12. Apart from this
|
||||
complication, the scheme is similar to the LDR above. */
|
||||
|
||||
if (opc == STR){
|
||||
reg2 = reg >> 12; /* Use R6 as the second register, */
|
||||
reg2 = (reg2 == 6 ? 0 : 6); /* or R0 if we can't */
|
||||
|
||||
tmpval = val - DOTVAL - 8;
|
||||
if (oursmall((tmpval & 0xFFFFF000) == 0, 24)){ /* If it's +ve */
|
||||
emit4(opc|ins|tmpval|0x018F0000); /* PC rel, up bit */
|
||||
return;
|
||||
}
|
||||
|
||||
tmpval *= -1;
|
||||
if (oursmall((tmpval & 0xFFFFF000) == 0, 24)){ /* If it's -ve */
|
||||
emit4(opc|ins|tmpval|0x010F0000); /* PC rel, no up bit */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bflag && pass == PASS_3){ /* Debugging info */
|
||||
/* warning("STR address extension"); */
|
||||
if (dflag)
|
||||
printf("value: %lx\n", val);
|
||||
}
|
||||
|
||||
opc = 0x03A00000; /* Set opc for putaddr */
|
||||
|
||||
if (oursmall((val & 0xFFFF0000) == 0, 8)){
|
||||
emit4(0xE92C0000|1<<reg2);
|
||||
putaddr(opc, (ins & 0xFFBF0FFF)|reg2<<12, val, 2);
|
||||
emit4(0x05000000|ins|reg2<<16);
|
||||
emit4(0xE8BC0000|1<<reg2);
|
||||
return;
|
||||
}
|
||||
if (oursmall((val & 0xFF000000) == 0, 4)){
|
||||
emit4(0xE92C0000|1<<reg2);
|
||||
putaddr(opc, (ins & 0xFFBF0FFF)|reg2<<12, val, 3);
|
||||
emit4(0x05000000|ins|reg2<<16);
|
||||
emit4(0xE8BC0000|1<<reg2);
|
||||
return;
|
||||
}
|
||||
emit4(0xE92C0000|1<<reg2);
|
||||
putaddr(opc, (ins & 0xFFBF0FFF)|reg2<<12, val, 4);
|
||||
emit4(0x05000000|ins|reg2<<16);
|
||||
emit4(0xE8BC0000|1<<reg2);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
word_t
|
||||
|
||||
/* This routine deals with ADR instructions. The ARM does not have a
|
||||
'calculate effective address' instruction, so we use ADD, SUB, MOV or
|
||||
MVN instead. ADR is not a genuine instruction, but is provided to make
|
||||
life easier. At present these are all calculated by using a MOV and
|
||||
successive ADDs. Even if the address will fit into a single MOV, we
|
||||
still use two instructions; the second is a no-op. This is to cure the
|
||||
optimisation problem with mobile addresses ! */
|
||||
|
||||
|
||||
calcadr(ins, reg, val, typ)
|
||||
word_t ins, reg;
|
||||
valu_t val;
|
||||
short typ;
|
||||
{
|
||||
valu_t tmpval = val;
|
||||
word_t opc;
|
||||
int i = 0;
|
||||
word_t opc = 0xff; /* Dummy opc used as a flag for data() */
|
||||
|
||||
if (typ != S_ABS){
|
||||
tmpval = val-DOTVAL-8;
|
||||
if (tmpval > 0) {
|
||||
if (small((tmpval & 0xFFFFFF00) == 0),12){
|
||||
emit4(ins|ADD|0x020F0000|reg<<12|tmpval);
|
||||
return 0;
|
||||
}
|
||||
/* First check that the address is in range */
|
||||
|
||||
if (val < 0)
|
||||
tmpval = ~tmpval; /* Invert negative addresses for check */
|
||||
|
||||
if ((tmpval & 0xFC000000) && (typ != S_UND)){
|
||||
serror("adr address out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
tmpval *= -1;
|
||||
if (small((tmpval & 0xFFFFFF00) == 0), 12){
|
||||
emit4(ins|SUB|0x020F0000|reg<<12|tmpval);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Can't do it PC relative, so use an absolute MOV instead */
|
||||
|
||||
tmpval = val;
|
||||
opc = MOV;
|
||||
if (calcimm(&opc, &tmpval, typ)){
|
||||
emit4(ins|opc|0x020F0000|reg<<12|tmpval);
|
||||
return 0;
|
||||
}
|
||||
data (opc, ins|reg<<12, val, typ);
|
||||
return;
|
||||
|
||||
/* Failed */
|
||||
if (pass == PASS_1)
|
||||
DOTVAL += 16;
|
||||
else
|
||||
serror("illegal ADR argument");
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
|
@ -246,9 +342,15 @@ valu_t val;
|
|||
short typ;
|
||||
word_t styp;
|
||||
{
|
||||
if (typ=S_UND) return 0;
|
||||
if (val & 0xFFFFFFE0) serror("shiftcount out of range");
|
||||
if (styp && !val) warning("shiftcount 0");
|
||||
if (typ == S_UND)
|
||||
return(0);
|
||||
|
||||
if (val & 0xFFFFFFE0)
|
||||
serror("shiftcount out of range");
|
||||
|
||||
if (styp && !val)
|
||||
warning("shiftcount 0");
|
||||
|
||||
return((val & 0x1F)<<7);
|
||||
}
|
||||
|
||||
|
@ -265,3 +367,144 @@ long *x;
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This routine overcomes the 12-bit encoding problem by outputting a number
|
||||
a byte at a time. For a MOV, it first uses a MOV, then successive ADDs.
|
||||
It will not use any more ADDs than needed to completely output the number.
|
||||
A similar approach is used for ADDs and SUBs.
|
||||
There is a problem here with optimisation in the third pass; if the
|
||||
instruction needed two ADDs in the second pass, but only one in the third
|
||||
pass, then the second ADD is replaced with a no-op. We cannot emit one
|
||||
less instruction, because that will upset other addresses.
|
||||
*/
|
||||
|
||||
putaddr(opc, ins, val, count)
|
||||
long opc, ins, val;
|
||||
int count;
|
||||
{
|
||||
long tmpval = val;
|
||||
long reg = ins & 0x0000F000;
|
||||
|
||||
emit4(opc|ins|(val & 0x000000FF));
|
||||
|
||||
tmpval = (val & 0x0000FF00) >> 8 | 0x00000C00;
|
||||
|
||||
/* Decide what to use for the additional instructions */
|
||||
|
||||
if (opc == 0x03a00000) /* This one is for strldr */
|
||||
opc = 0x02800000;
|
||||
|
||||
if (opc == MOV)
|
||||
opc = ADD;
|
||||
|
||||
if (opc == MVN)
|
||||
opc = SUB;
|
||||
|
||||
if ((tmpval & 0x000000FF) != 0)
|
||||
emit4(opc|ins|reg<<4|tmpval);
|
||||
else
|
||||
emit4(0xF0000000); /* No-op if a zero argument */
|
||||
|
||||
if (count == 3 || count == 4){ /* Must use three or more instructions */
|
||||
if ((val & 0xFFFF0000) != 0){
|
||||
tmpval = (val & 0x00FF0000) >> 16 | 0x00000800;
|
||||
emit4(opc|ins|reg<<4|tmpval);
|
||||
}
|
||||
else
|
||||
emit4(0xF0000000); /* No-op */
|
||||
}
|
||||
|
||||
if (count == 4){ /* Must use four instructions */
|
||||
if ((val & 0xFF000000) != 0){
|
||||
tmpval = (val & 0xFF000000) >> 24 | 0x00000400;
|
||||
emit4(opc|ins|reg<<4|tmpval);
|
||||
}
|
||||
else
|
||||
emit4(0xF0000000); /* No-op */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* The following piece of code is stolen from comm7.c; it needs some minor
|
||||
fixes for the ARM, so it is included here rather than altering the existing
|
||||
code. It maintains a bit table to say whether or not an optimisation is
|
||||
possible. The original had some problems:
|
||||
(a). It assumed that the memory returned by malloc() was cleared to zero.
|
||||
This is true on a Sun, but not under Minix; small() should really
|
||||
use calloc() instead.
|
||||
(b). It assumed that if an optimisation was possible in pass 2, it must
|
||||
also be possible in pass 3, and produced an assertion error if it
|
||||
wasn't. This is OK for optimising things like long or short branch
|
||||
instructions on a 68000, but not for ADRs on the ARM. A previous
|
||||
optimisation may place an address out of 12-bit encoding range on
|
||||
pass 3, when it was in range on pass 2. However we have to be
|
||||
careful here .....
|
||||
*/
|
||||
|
||||
#define PBITTABSZ 128
|
||||
static char *pbittab[PBITTABSZ];
|
||||
|
||||
oursmall(fitsmall, gain)
|
||||
{
|
||||
register bit;
|
||||
register char *p;
|
||||
|
||||
if (DOTSCT == NULL)
|
||||
nosect();
|
||||
if (bflag)
|
||||
return(0);
|
||||
if (nbits == BITCHUNK) {
|
||||
bitindex++;
|
||||
nbits = 0;
|
||||
if (bitindex == PBITTABSZ) {
|
||||
static int w_given;
|
||||
if (pass == PASS_1 && ! w_given) {
|
||||
w_given = 1;
|
||||
warning("bit table overflow");
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
if (pbittab[bitindex] == 0 && pass == PASS_1) {
|
||||
if ((pbittab[bitindex] = malloc(MEMINCR)) == 0) {
|
||||
static int w2_given;
|
||||
|
||||
if (!w2_given) {
|
||||
w2_given = 1;
|
||||
warning("out of space for bit table");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pbittab[bitindex] == 0)
|
||||
return (0);
|
||||
}
|
||||
bit = 1 << (nbits&7);
|
||||
p = pbittab[bitindex]+(nbits>>3);
|
||||
nbits++;
|
||||
|
||||
switch (pass) {
|
||||
case PASS_1:
|
||||
*p = 0;
|
||||
return(0);
|
||||
case PASS_2:
|
||||
if (fitsmall) {
|
||||
DOTGAIN += gain;
|
||||
*p |= bit;
|
||||
}
|
||||
return(fitsmall);
|
||||
case PASS_3:
|
||||
if (!(fitsmall || (*p & bit) == 0)){
|
||||
printf("line: %ld - small failed\n", lineno);
|
||||
printf("fitsmall: %d bit: %d\n", fitsmall, (*p & bit));
|
||||
if (fitsmall)
|
||||
return(0);
|
||||
else
|
||||
serror("This one is fatal!");
|
||||
}
|
||||
return(*p & bit);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue