/* rx-parse.y Renesas RX parser
- Copyright 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2008-2015 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#define F(val,pos,sz) rx_field (val, pos, sz)
#define FE(exp,pos,sz) rx_field (exp_val (exp), pos, sz);
-#define O1(v) rx_op (v, 1, RXREL_SIGNED)
-#define O2(v) rx_op (v, 2, RXREL_SIGNED)
-#define O3(v) rx_op (v, 3, RXREL_SIGNED)
+#define O1(v) rx_op (v, 1, RXREL_SIGNED); rx_range (v, -128, 255)
+#define O2(v) rx_op (v, 2, RXREL_SIGNED); rx_range (v, -32768, 65536)
+#define O3(v) rx_op (v, 3, RXREL_SIGNED); rx_range (v, -8388608, 16777216)
#define O4(v) rx_op (v, 4, RXREL_SIGNED)
-#define UO1(v) rx_op (v, 1, RXREL_UNSIGNED)
-#define UO2(v) rx_op (v, 2, RXREL_UNSIGNED)
-#define UO3(v) rx_op (v, 3, RXREL_UNSIGNED)
+#define UO1(v) rx_op (v, 1, RXREL_UNSIGNED); rx_range (v, 0, 255)
+#define UO2(v) rx_op (v, 2, RXREL_UNSIGNED); rx_range (v, 0, 65536)
+#define UO3(v) rx_op (v, 3, RXREL_UNSIGNED); rx_range (v, 0, 16777216)
#define UO4(v) rx_op (v, 4, RXREL_UNSIGNED)
#define NO1(v) rx_op (v, 1, RXREL_NEGATIVE)
#define PC2(v) rx_op (v, 2, RXREL_PCREL)
#define PC3(v) rx_op (v, 3, RXREL_PCREL)
-#define IMM(v,pos) F (immediate (v, RXREL_SIGNED, pos), pos, 2); \
+#define IMM_(v,pos,size) F (immediate (v, RXREL_SIGNED, pos, size), pos, 2); \
if (v.X_op != O_constant && v.X_op != O_big) rx_linkrelax_imm (pos)
-#define NIMM(v,pos) F (immediate (v, RXREL_NEGATIVE, pos), pos, 2)
-#define NBIMM(v,pos) F (immediate (v, RXREL_NEGATIVE_BORROW, pos), pos, 2)
+#define IMM(v,pos) IMM_ (v, pos, 32)
+#define IMMW(v,pos) IMM_ (v, pos, 16); rx_range (v, -32768, 65536)
+#define IMMB(v,pos) IMM_ (v, pos, 8); rx_range (v, -128, 255)
+#define NIMM(v,pos) F (immediate (v, RXREL_NEGATIVE, pos, 32), pos, 2)
+#define NBIMM(v,pos) F (immediate (v, RXREL_NEGATIVE_BORROW, pos, 32), pos, 2)
#define DSP(v,pos,msz) if (!v.X_md) rx_relax (RX_RELAX_DISP, pos); \
else rx_linkrelax_dsp (pos); \
F (displacement (v, msz), pos, 2)
#define id24(a,b2,b3) B3 (0xfb+a, b2, b3)
-static int rx_intop (expressionS, int);
+static void rx_check_float_support (void);
+static int rx_intop (expressionS, int, int);
static int rx_uintop (expressionS, int);
static int rx_disp3op (expressionS);
static int rx_disp5op (expressionS *, int);
static int rx_disp5op0 (expressionS *, int);
static int exp_val (expressionS exp);
static expressionS zero_expr (void);
-static int immediate (expressionS, int, int);
+static int immediate (expressionS, int, int, int);
static int displacement (expressionS, int);
static void rtsd_immediate (expressionS);
+static void rx_range (expressionS, int, int);
static int need_flag = 0;
static int rx_in_brackets = 0;
| BRA EXPR
{ if (rx_disp3op ($2))
{ B1 (0x08); rx_disp3 ($2, 5); }
- else if (rx_intop ($2, 8))
+ else if (rx_intop ($2, 8, 8))
{ B1 (0x2e); PC1 ($2); }
- else if (rx_intop ($2, 16))
+ else if (rx_intop ($2, 16, 16))
{ B1 (0x38); PC2 ($2); }
- else if (rx_intop ($2, 24))
+ else if (rx_intop ($2, 24, 24))
{ B1 (0x04); PC3 ($2); }
else
{ rx_relax (RX_RELAX_BRANCH, 0);
/* ---------------------------------------------------------------------- */
| BSR EXPR
- { if (rx_intop ($2, 16))
+ { if (rx_intop ($2, 16, 16))
{ B1 (0x39); PC2 ($2); }
- else if (rx_intop ($2, 24))
+ else if (rx_intop ($2, 24, 24))
{ B1 (0x05); PC3 ($2); }
else
{ rx_relax (RX_RELAX_BRANCH, 0);
{ if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, WSIZE))
{ B2 (0x3d, 0); rx_field5s2 ($6); F ($8, 9, 3); O1 ($4); }
else
- { B2 (0xf8, 0x01); F ($8, 8, 4); DSP ($6, 6, WSIZE); IMM ($4, 12); } }
+ { B2 (0xf8, 0x01); F ($8, 8, 4); DSP ($6, 6, WSIZE); IMMW ($4, 12); } }
| MOV DOT_L '#' EXPR ',' disp '[' REG ']'
{ if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, LSIZE))
{ B2 (0x60, 0); FE ($3, 8, 4); F ($5, 12, 4); }
else
/* This is really an add, but we negate the immediate. */
- { B2 (0x38, 0); F ($5, 8, 4); F ($5, 12, 4); NIMM ($3, 6); } } /* ? */
+ { B2 (0x70, 0); F ($5, 8, 4); F ($5, 12, 4); NIMM ($3, 6); } }
| CMP '#' EXPR ',' REG
{ if (rx_uintop ($3, 4))
/* ---------------------------------------------------------------------- */
| MVTIPL '#' EXPR
- { B2 (0x7f, 0x98); FE ($3, 13, 3); }
+ { B3 (0x75, 0x70, 0x00); FE ($3, 20, 4); }
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
- | SBB { sub_op = 0; } op_dp20_rm
- | NEG { sub_op = 1; sub_op2 = 1; } op_dp20_rms
- | ADC { sub_op = 2; } op_dp20_rim
- | ABS { sub_op = 3; sub_op2 = 2; } op_dp20_rms
+ | SBB { sub_op = 0; } op_dp20_rm_l
+ | NEG { sub_op = 1; sub_op2 = 1; } op_dp20_rr
+ | ADC { sub_op = 2; } op_dp20_rim_l
+ | ABS { sub_op = 3; sub_op2 = 2; } op_dp20_rr
| MAX { sub_op = 4; } op_dp20_rim
| MIN { sub_op = 5; } op_dp20_rim
| EMUL { sub_op = 6; } op_dp20_i
| DIVU { sub_op = 9; } op_dp20_rim
| TST { sub_op = 12; } op_dp20_rim
| XOR { sub_op = 13; } op_dp20_rim
- | NOT { sub_op = 14; sub_op2 = 0; } op_dp20_rms
+ | NOT { sub_op = 14; sub_op2 = 0; } op_dp20_rr
| STZ { sub_op = 14; } op_dp20_i
| STNZ { sub_op = 15; } op_dp20_i
| BNOT REG ',' REG
{ id24 (1, 0x6f, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
- | BSET REG ',' disp '[' REG ']' DOT_B
+ | BSET REG ',' disp '[' REG ']' opt_b
{ id24 (1, 0x60, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
- | BCLR REG ',' disp '[' REG ']' DOT_B
+ | BCLR REG ',' disp '[' REG ']' opt_b
{ id24 (1, 0x64, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
- | BTST REG ',' disp '[' REG ']' DOT_B
+ | BTST REG ',' disp '[' REG ']' opt_b
{ id24 (1, 0x68, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
- | BNOT REG ',' disp '[' REG ']' DOT_B
+ | BNOT REG ',' disp '[' REG ']' opt_b
{ id24 (1, 0x6c, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
- | BMCND '#' EXPR ',' disp '[' REG ']' DOT_B
+ | BMCND '#' EXPR ',' disp '[' REG ']' opt_b
{ id24 (1, 0xe0, 0x00); F ($1, 20, 4); FE ($3, 11, 3);
F ($7, 16, 4); DSP ($5, 14, BSIZE); }
/* ---------------------------------------------------------------------- */
- | BNOT '#' EXPR ',' disp '[' REG ']' DOT_B
+ | BNOT '#' EXPR ',' disp '[' REG ']' opt_b
{ id24 (1, 0xe0, 0x0f); FE ($3, 11, 3); F ($7, 16, 4);
DSP ($5, 14, BSIZE); }
/* sbb, neg, adc, abs, max, min, div, divu, tst, not, xor, stz, stnz, emul, emulu */
+op_dp20_rm_l
+ : REG ',' REG
+ { id24 (1, 0x03 + (sub_op<<2), 0x00); F ($1, 16, 4); F ($3, 20, 4); }
+ | disp '[' REG ']' opt_l ',' REG
+ { B4 (MEMEX, 0xa0, 0x00 + sub_op, 0x00);
+ F ($3, 24, 4); F ($7, 28, 4); DSP ($1, 14, LSIZE); }
+ ;
+
+/* neg, adc, abs, max, min, div, divu, tst, not, xor, stz, stnz, emul, emulu */
+
op_dp20_rm
: REG ',' REG
{ id24 (1, 0x03 + (sub_op<<2), 0x00); F ($1, 16, 4); F ($3, 20, 4); }
| op_dp20_i
;
-op_dp20_rms
- : op_dp20_rm
+op_dp20_rim_l
+ : op_dp20_rm_l
+ | op_dp20_i
+ ;
+
+op_dp20_rr
+ : REG ',' REG
+ { id24 (1, 0x03 + (sub_op<<2), 0x00); F ($1, 16, 4); F ($3, 20, 4); }
| REG
{ B2 (0x7e, sub_op2 << 4); F ($1, 12, 4); }
;
;
-
float2_op
- : '#' EXPR ',' REG
- { id24 (2, 0x72, sub_op << 4); F ($4, 20, 4); O4 ($2); }
+ : { rx_check_float_support (); }
+ '#' EXPR ',' REG
+ { id24 (2, 0x72, sub_op << 4); F ($5, 20, 4); O4 ($3); }
| float2_op_ni
;
+
float2_op_ni
- : REG ',' REG
- { id24 (1, 0x83 + (sub_op << 2), 0); F ($1, 16, 4); F ($3, 20, 4); }
- | disp '[' REG ']' opt_l ',' REG
- { id24 (1, 0x80 + (sub_op << 2), 0); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, LSIZE); }
+ : { rx_check_float_support (); }
+ REG ',' REG
+ { id24 (1, 0x83 + (sub_op << 2), 0); F ($2, 16, 4); F ($4, 20, 4); }
+ | { rx_check_float_support (); }
+ disp '[' REG ']' opt_l ',' REG
+ { id24 (1, 0x80 + (sub_op << 2), 0); F ($4, 16, 4); F ($8, 20, 4); DSP ($2, 14, LSIZE); }
;
/* ====================================================================== */
| DOT_L {}
;
+opt_b : {}
+ | DOT_B {}
+ ;
+
%%
/* ====================================================================== */
{ "pc", CREG, 1 },
{ "usp", CREG, 2 },
{ "fpsw", CREG, 3 },
- { "cpen", CREG, 4 },
+ /* reserved */
/* reserved */
/* reserved */
{ "wr", CREG, 7 },
return 0;
if (ISALPHA (*rx_lex_start)
+ || (rx_pid_register != -1 && memcmp (rx_lex_start, "%pidreg", 7) == 0)
+ || (rx_gp_register != -1 && memcmp (rx_lex_start, "%gpreg", 6) == 0)
|| (*rx_lex_start == '.' && ISALPHA (rx_lex_start[1])))
{
unsigned int i;
save = *e;
*e = 0;
+ if (strcmp (rx_lex_start, "%pidreg") == 0)
+ {
+ {
+ rx_lval.regno = rx_pid_register;
+ *e = save;
+ rx_lex_start = e;
+ rx_last_token = REG;
+ return REG;
+ }
+ }
+
+ if (strcmp (rx_lex_start, "%gpreg") == 0)
+ {
+ {
+ rx_lval.regno = rx_gp_register;
+ *e = save;
+ rx_lex_start = e;
+ rx_last_token = REG;
+ return REG;
+ }
+ }
+
if (rx_last_token == 0)
for (ci = 0; ci < NUM_CONDITION_OPCODES; ci ++)
if (check_condition (condition_opcode_table[ci].string))
}
int
-rx_error (char * str)
+rx_error (const char * str)
{
int len;
}
static int
-rx_intop (expressionS exp, int nbits)
+rx_intop (expressionS exp, int nbits, int opbits)
{
long v;
+ long mask, msb;
if (exp.X_op == O_big && nbits == 32)
return 1;
return 0;
v = exp.X_add_number;
+ msb = 1UL << (opbits - 1);
+ mask = (1UL << opbits) - 1;
+
+ if ((v & msb) && ! (v & ~mask))
+ v -= 1UL << opbits;
+
switch (nbits)
{
case 4:
}
static int
-immediate (expressionS exp, int type, int pos)
+immediate (expressionS exp, int type, int pos, int bits)
{
/* We will emit constants ourself here, so negate them. */
if (type == RXREL_NEGATIVE && exp.X_op == O_constant)
rx_error (_("sbb cannot use symbolic immediates"));
}
- if (rx_intop (exp, 8))
+ if (rx_intop (exp, 8, bits))
{
rx_op (exp, 1, type);
return 1;
}
- else if (rx_intop (exp, 16))
+ else if (rx_intop (exp, 16, bits))
{
rx_op (exp, 2, type);
return 2;
}
- else if (rx_intop (exp, 24))
+ else if (rx_uintop (exp, 16) && bits == 16)
+ {
+ rx_op (exp, 2, type);
+ return 2;
+ }
+ else if (rx_intop (exp, 24, bits))
{
rx_op (exp, 3, type);
return 3;
}
- else if (rx_intop (exp, 32))
+ else if (rx_intop (exp, 32, bits))
{
rx_op (exp, 4, type);
return 0;
}
}
+ if (exp.X_op == O_subtract)
+ {
+ exp.X_md = BFD_RELOC_RX_DIFF;
+ O2 (exp);
+ return 2;
+ }
+
if (exp.X_op != O_constant)
{
rx_error (_("displacements must be constants"));
exp.X_add_number = val;
O1 (exp);
}
+
+static void
+rx_range (expressionS exp, int minv, int maxv)
+{
+ int val;
+
+ if (exp.X_op != O_constant)
+ return;
+
+ val = exp.X_add_number;
+ if (val < minv || val > maxv)
+ as_warn (_("Value %d out of range %d..%d"), val, minv, maxv);
+}
+
+static void
+rx_check_float_support (void)
+{
+ if (rx_cpu == RX100 || rx_cpu == RX200)
+ rx_error (_("target CPU type does not support floating point instructions"));
+}