ack/mach/powerpc/as/mach4.c
George Koehler b1badf1851 Add instructions like "lwarx". Extend manual.
Add more page numbers from PowerPC version 2.01.  Remove "xnop" not in
2.01, add "mtcr" from 2.01.  Add "lwarx" and the other instructions
from Book II.  I did not try all the newly added instructions, but
these seem to work: dcbt, dcbtst, icibi, isync, lwarx, stwcx., mftb,
mftbu

In man/powerpc_as.6 (not installed), add a summary of the registers
and addressing modes (like in i386_as.6), describe short forms, update
description of hi16/ha16, add CAVEATS about instructions that some
processors can't run.
2018-03-07 13:37:31 -05:00

452 lines
14 KiB
C

/*
* $Source$
* $State$
*/
operation
: OP { emit4($1); }
| OP_BDA bda { emit4($1 | $2); }
| OP_BDL bdl { emit4($1 | $2); }
| OP_BF_BFA CR ',' CR { emit4($1 | ($2<<23) | ($4<<18)); }
| OP_BF_FRA_FRB CR ',' FPR ',' FPR { emit4($1 | ($2<<23) | ($4<<16) | ($6<<11)); }
| OP_BF_L_RA_RB CR ',' u1 ',' GPR ',' GPR { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | ($8<<11)); }
| OP_BF_L_RA_SI CR ',' u1 ',' GPR ',' e16 { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
| OP_BF_L_RA_UI CR ',' u1 ',' GPR ',' e16 { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
| OP_BF_RA_RB cr_opt GPR ',' GPR { emit4($1 | ($2<<23) | ($3<<16) | ($5<<11)); }
| OP_BF_RA_SI cr_opt GPR ',' e16 { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
| OP_BF_RA_UI cr_opt GPR ',' e16 { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
| OP_BF_U_C c CR ',' u4 { emit4($1 | $2 | ($3<<23) | ($5<<12)); }
| OP_BH { emit4($1); }
| OP_BH u2 { emit4($1 | ($2<<11)); }
| OP_BI_BDA u5 ',' bda { emit4($1 | ($2<<16) | $4); }
| OP_BI_BDL u5 ',' bdl { emit4($1 | ($2<<16) | $4); }
| OP_BI_BH u5 opt_bh { emit4($1 | ($2<<16) | $3); }
| OP_BICR_BDA cr_opt bda { emit4($1 | ($2<<18) | $3); }
| OP_BICR_BDL cr_opt bdl { emit4($1 | ($2<<18) | $3); }
| OP_BICR_BH { emit4($1); }
| OP_BICR_BH CR opt_bh { emit4($1 | ($2<<18) | $3); }
| OP_BO_BI_BDA u5 ',' u5 ',' bda { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_BO_BI_BDL u5 ',' u5 ',' bdl { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_BO_BI_BH u5 ',' u5 opt_bh { emit4($1 | ($2<<21) | ($4<<16) | $5); }
| OP_BT_BA_BA u5 ',' u5 { emit4($1 | ($2<<21) | ($4<<16) | ($4<<11)); }
| OP_BT_BA_BB u5 ',' u5 ',' u5 { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_BT_BT_BT u5 { emit4($1 | ($2<<21) | ($2<<16) | ($2<<11)); }
| OP_BT_C c u5 { emit4($1 | $2 | ($3<<21)); }
| OP_FLM_FRB_C c u8 ',' FPR { emit4($1 | $2 | ($3<<17) | ($5<<11)); }
| OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_FRS_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_FRA_FRB_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
| OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); }
| OP_FRT_FRA_FRC_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); }
| OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); }
| OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_FRT_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); }
| OP_L { emit4($1); }
| OP_L u2 { emit4($1 | ($2<<21)); }
| OP_LEV { emit4($1); }
| OP_LEV u7 { emit4($1 | ($2<<5)); }
| OP_RA_RB GPR ',' GPR
{ emit4($1 | ($2<<16) | ($4<<11)); }
| OP_RA_RB_TH GPR ',' GPR opt_bh
{ emit4($1 | $5 | ($2<<16) | ($4<<11)); }
/*
* For instructions with "mnemonic RS, RA, ..."
* OP_RA_RS_... swaps RS and RA to (RA<<21) || (RS<<16)
* OP_RS_RA_... keeps RS and RA as (RS<<21) || (RA<<16)
*/
| OP_RA_RS_C c GPR ',' GPR
{ emit4($1 | $2 | ($5<<21) | ($3<<16)); }
| OP_RA_RS_RA_C c GPR ',' GPR
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); }
| OP_RA_RS_RB_C c GPR ',' GPR ',' GPR
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
| OP_RA_RS_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) |
($9<<6) | ($11<<1)); }
| OP_RA_RS_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | MB6($9)); }
| OP_RA_RS_SH5_C c GPR ',' GPR ',' u5
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
| OP_RA_RS_SH5_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5
{ emit4($1 | $2 | ($5<<21) | ($3<<16) |
($7<<11) | ($9<<6) | ($11<<1)); }
| OP_RA_RS_SH6_C c GPR ',' GPR ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7)); }
| OP_RA_RS_SH6_MB6_C c GPR ',' GPR ',' u6 ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6($9)); }
| OP_RA_RS_UI GPR ',' GPR ',' e16 { emit_hl($1 | ($4<<21) | ($2<<16) | $6); }
| OP_RA_RS_UI_CC C GPR ',' GPR ',' e16 { emit_hl($1 | ($5<<21) | ($3<<16) | $7); }
| OP_RT GPR { emit4($1 | ($2<<21)); }
| OP_RT_RA_C c GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16)); }
| OP_RT_RA_D GPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RT_RA_DS GPR ',' ds '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RT_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RT_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RT_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
| OP_RT_RA_SI GPR ',' GPR ',' e16 { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
| OP_RT_RA_SI_addic c GPR ',' GPR ',' e16 { emit_hl($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
| OP_RT_RA_SI_subi GPR ',' GPR ',' negate16 { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_RT_RA_SI_subic c GPR ',' GPR ',' negate16 { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
| OP_RT_RB_RA_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($7<<16) | ($5<<11)); }
| OP_RT_SI GPR ',' e16 { emit_hl($1 | ($2<<21) | $4); }
| OP_RT_SPR GPR ',' spr_num { emit4($1 | ($2<<21) | ($4<<11)); }
| OP_RT_TBR GPR opt_tbr { emit4($1 | ($2<<21) | ($3<<11)); }
| OP_RS GPR { emit4($1 | ($2<<21)); }
| OP_RS_FXM u7 ',' GPR { emit4($1 | ($4<<21) | ($2<<12)); }
| OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RS_RA_RB_CC C GPR ',' GPR ',' GPR { emit4($1 | ($3<<21) | ($5<<16) | ($7<<11)); }
| OP_RS_SPR spr_num ',' GPR { emit4($1 | ($4<<21) | ($2<<11)); }
| OP_TO_RA_RB u5 ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_TO_RA_SI u5 ',' GPR ',' e16 { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
| OP_TOX_RA_RB GPR ',' GPR { emit4($1 | ($2<<16) | ($4<<11)); }
| OP_TOX_RA_SI GPR ',' e16 { emit_hl($1 | ($2<<16) | $4); }
| OP_LIA lia { emit4($1 | $2); }
| OP_LIL lil { emit4($1 | $2); }
| OP_LI32 li32 /* emitted in subrule */
| OP_clrlsldi c GPR ',' GPR ',' u6 ',' u6
{
word_t mb = ($7 - $9) & 0x3f;
fit($9 <= $7);
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($9) | MB6(mb));
}
| OP_clrldi c GPR ',' GPR ',' u6
{
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(0) | MB6($7));
}
| OP_clrrdi c GPR ',' GPR ',' u6
{
word_t me = 63 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(0) | MB6(me));
}
| OP_extldi c GPR ',' GPR ',' u6 ',' u6
{
word_t me = ($7 - 1) & 0x3f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($9) | MB6(me));
}
| OP_extrdi c GPR ',' GPR ',' u6 ',' u6
{
word_t sh = ($9 + $7) & 0x3f;
word_t mb = (64 - $7) & 0x3f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6(mb));
}
| OP_rotrdi c GPR ',' GPR ',' u6
{
word_t sh = (64 - $7) & 0x3f;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6(0));
}
| OP_sldi c GPR ',' GPR ',' u6
{
word_t me = 63 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6(me));
}
| OP_srdi c GPR ',' GPR ',' u6
{
word_t sh = (64 - $7) & 0x3f;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6($7));
}
| OP_clrlslwi c GPR ',' GPR ',' u5 ',' u5
{
word_t mb = ($7 - $9) & 0x1f;
word_t me = 31 - $9;
fit($9 <= $7);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
($9<<11) | (mb<<6) | (me<<1));
}
| OP_clrlwi c GPR ',' GPR ',' u5
{
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(0<<11) | ($7<<6) | (31<<1));
}
| OP_clrrwi c GPR ',' GPR ',' u5
{
word_t me = 31 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(0<<11) | (0<<6) | (me<<1));
}
| OP_extlwi c GPR ',' GPR ',' u5 ',' u5
{
word_t me = ($7 - 1) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
($9<<11) | (0<<6) | (me<<1));
}
| OP_extrwi c GPR ',' GPR ',' u5 ',' u5
{
word_t sh = ($9 + $7) & 0x1f;
word_t mb = (32 - $7) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | (mb<<6) | (31<<1));
}
| OP_inslwi c GPR ',' GPR ',' u5 ',' u5
{
word_t sh = (32 - $9) & 0x1f;
word_t me = ($9 + $7 - 1) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | ($9<<6) | (me<<1));
}
| OP_insrwi c GPR ',' GPR ',' u5 ',' u5
{
word_t sh = (32 - $9 - $7) & 0x1f;
word_t me = ($9 + $7 - 1) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | ($9<<6) | (me<<1));
}
| OP_rotrwi c GPR ',' GPR ',' u5
{
word_t sh = (32 - $7) & 0x1f;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | (0<<6) | (31<<1));
}
| OP_slwi c GPR ',' GPR ',' u5
{
word_t me = 31 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
($7<<11) | (0<<6) | (me<<1));
}
| OP_srwi c GPR ',' GPR ',' u5
{
word_t sh = (32 - $7) & 0x1f;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | ($7<<6) | (31<<1));
}
;
c
: /* nothing */ { $$ = 0; }
| C { $$ = 1; }
;
e16
: absexp
{
/* Allow signed or unsigned 16-bit values. */
if (($1 < -0x8000) || ($1 > 0xffff))
serror("16-bit value out of range");
$$ = (uint16_t) $1;
no_hl();
}
| OP_HI ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_HI); }
| OP_HA ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_HA); }
| OP_LO ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_LO); }
;
negate16
: absexp
{
/* To encode subi, we negate the immediate value, then
* it must fit as signed 16-bit. */
$$ = -$1;
fit(fitx($$, 16));
$$ = (uint16_t) $$;
}
;
u8
: absexp
{
if (($1 < 0) || ($1 > 0xFF))
serror("8-bit unsigned value out of range");
$$ = $1;
}
;
u7
: absexp
{
if (($1 < 0) || ($1 > 0x7F))
serror("7-bit unsigned value out of range");
$$ = $1;
}
;
u6
: absexp
{
if (($1 < 0) || ($1 > 0x3F))
serror("6-bit unsigned value out of range");
$$ = $1;
}
;
u5
: absexp
{
if (($1 < 0) || ($1 > 0x1F))
serror("5-bit unsigned value out of range");
$$ = $1;
}
;
u4
: absexp
{
if (($1 < 0) || ($1 > 0xF))
serror("4-bit unsigned value out of range");
$$ = $1;
}
;
u1
: absexp
{
if (($1 < 0) || ($1 > 1))
serror("1-bit unsigned value out of range");
$$ = $1;
}
;
u2
: absexp
{
if (($1 < 0) || ($1 > 0x3))
serror("2-bit unsigned value out of range");
$$ = $1;
}
;
/* Optional comma, branch hint (or touch hint). */
opt_bh
: /* nothing */ { $$ = 0; }
| ',' u2 { $$ = ($2<<11); }
/*
* Optional condition register, comma. This checks if the token is a
* CR register name. This wouldn't work if we allowed CR as a number.
*/
cr_opt
: /* nothing */ { $$ = 0; }
| CR ',' { $$ = $1; }
ds
: e16
{
if ($1 & 3)
serror("value must be 4-aligned");
$$ = $1;
}
;
nb
: absexp
{
if (($1 < 1) || ($1 > 32))
serror("register count must be in the range 1..32");
if ($1 == 32)
$$ = 0;
else
$$ = $1;
}
;
bdl
: expr
{
int dist = $1.val - DOTVAL;
fit(fitx(dist, 25));
if (dist & 0x3)
serror("jump targets must be 4-aligned");
DOTVAL += 2;
newrelo($1.typ, RELO2 | RELPC | FIXUPFLAGS);
DOTVAL -= 2;
$$ = dist & 0xFFFD;
}
;
bda
: expr
{
int target = $1.val;
fit(fitx(target, 16));
if (target & 0x3)
serror("jump targets must be 4-aligned");
DOTVAL += 2;
newrelo($1.typ, RELO2 | FIXUPFLAGS);
DOTVAL -= 2;
$$ = target & 0xFFFD;
}
;
li32
: GPR ',' expr
{
word_t type = $3.typ & S_TYP;
word_t val = $3.val;
if ((type == S_ABS) && (val <= 0xffff))
emit4((14<<26) | ($1<<21) | (0<<16) | val); /* addi */
else
{
newrelo($3.typ, RELOPPC | FIXUPFLAGS);
emit4((15<<26) | ($1<<21) | (0<<16) | (val >> 16)); /* addis */
emit4((24<<26) | ($1<<21) | ($1<<16) | (val & 0xffff)); /* ori */
}
}
;
lil
: expr
{
int dist = $1.val - DOTVAL;
fit(fitx(dist, 26));
if (dist & 0x3)
serror("jump targets must be 4-aligned");
newrelo($1.typ, RELOPPC | RELPC | FIXUPFLAGS);
$$ = dist & 0x03FFFFFD;
}
;
lia
: expr
{
int target = $1.val;
fit(fitx(target, 26));
if (target & 0x3)
serror("jump targets must be 4-aligned");
newrelo($1.typ, RELOPPC | FIXUPFLAGS);
$$ = target & 0x03FFFFFD;
}
;
/*
* Instructions "mfspr", "mtspr", and "mftb" encode the 10-bit special
* purpose register (spr) or time base register (tbr) by swapping the
* low 5 bits with the high 5 bits. The value from an SPR token has
* already been swapped.
*/
spr_num
: SPR { $$ = $1; }
| tbr_num { $$ = $1; }
;
opt_tbr
: /* nothing */ { $$ = 8 | (12<<5); }
| ',' tbr_num { $$ = $2; }
;
tbr_num
: absexp
{
if (($1 < 0) || ($1 > 0x3ff))
serror("10-bit unsigned value out of range");
$$ = ($1 >> 5) | (($1 & 0x1f) << 5);
}
;