aboutsummaryrefslogtreecommitdiff
path: root/gas/config/rx-parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/rx-parse.y')
-rw-r--r--gas/config/rx-parse.y1555
1 files changed, 1555 insertions, 0 deletions
diff --git a/gas/config/rx-parse.y b/gas/config/rx-parse.y
new file mode 100644
index 0000000..0bcafc8
--- /dev/null
+++ b/gas/config/rx-parse.y
@@ -0,0 +1,1555 @@
+/* rx-parse.y Renesas RX parser
+ Copyright 2008, 2009
+ Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+%{
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "rx-defs.h"
+
+static int rx_lex (void);
+
+#define COND_EQ 0
+#define COND_NE 1
+
+#define MEMEX 0x06
+
+#define BSIZE 0
+#define WSIZE 1
+#define LSIZE 2
+
+/* .sb .sw .l .uw */
+static int sizemap[] = { BSIZE, WSIZE, LSIZE, WSIZE };
+
+/* Ok, here are the rules for using these macros...
+
+ B*() is used to specify the base opcode bytes. Fields to be filled
+ in later, leave zero. Call this first.
+
+ F() and FE() are used to fill in fields within the base opcode bytes. You MUST
+ call B*() before any F() or FE().
+
+ [UN]*O*(), PC*() appends operands to the end of the opcode. You
+ must call P() and B*() before any of these, so that the fixups
+ have the right byte location.
+ O = signed, UO = unsigned, NO = negated, PC = pcrel
+
+ IMM() adds an immediate and fills in the field for it.
+ NIMM() same, but negates the immediate.
+ NBIMM() same, but negates the immediate, for sbb.
+ DSP() adds a displacement, and fills in the field for it.
+
+ Note that order is significant for the O, IMM, and DSP macros, as
+ they append their data to the operand buffer in the order that you
+ call them.
+
+ Use "disp" for displacements whenever possible; this handles the
+ "0" case properly. */
+
+#define B1(b1) rx_base1 (b1)
+#define B2(b1, b2) rx_base2 (b1, b2)
+#define B3(b1, b2, b3) rx_base3 (b1, b2, b3)
+#define B4(b1, b2, b3, b4) rx_base4 (b1, b2, b3, b4)
+
+/* POS is bits from the MSB of the first byte to the LSB of the last byte. */
+#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 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 UO4(v) rx_op (v, 4, RXREL_UNSIGNED)
+
+#define NO1(v) rx_op (v, 1, RXREL_NEGATIVE)
+#define NO2(v) rx_op (v, 2, RXREL_NEGATIVE)
+#define NO3(v) rx_op (v, 3, RXREL_NEGATIVE)
+#define NO4(v) rx_op (v, 4, RXREL_NEGATIVE)
+
+#define PC1(v) rx_op (v, 1, RXREL_PCREL)
+#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); \
+ 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 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 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 displacement (expressionS, int);
+static void rtsd_immediate (expressionS);
+
+static int need_flag = 0;
+static int rx_in_brackets = 0;
+static int rx_last_token = 0;
+static char * rx_init_start;
+static char * rx_last_exp_start = 0;
+static int sub_op;
+static int sub_op2;
+
+#define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+
+%}
+
+%name-prefix="rx_"
+
+%union {
+ int regno;
+ expressionS exp;
+}
+
+%type <regno> REG FLAG CREG BCND BMCND SCCND
+%type <regno> flag bwl bw memex
+%type <exp> EXPR disp
+
+%token REG FLAG CREG
+
+%token EXPR UNKNOWN_OPCODE IS_OPCODE
+
+%token DOT_S DOT_B DOT_W DOT_L DOT_A DOT_UB DOT_UW
+
+%token ABS ADC ADD AND_
+%token BCLR BCND BMCND BNOT BRA BRK BSET BSR BTST
+%token CLRPSW CMP
+%token DBT DIV DIVU
+%token EDIV EDIVU EMUL EMULU
+%token FADD FCMP FDIV FMUL FREIT FSUB FTOI
+%token INT ITOF
+%token JMP JSR
+%token MACHI MACLO MAX MIN MOV MOVU MUL MULHI MULLO MULU MVFACHI MVFACMI MVFACLO
+%token MVFC MVTACHI MVTACLO MVTC MVTIPL
+%token NEG NOP NOT
+%token OR
+%token POP POPC POPM PUSH PUSHA PUSHC PUSHM
+%token RACW REIT REVL REVW RMPA ROLC RORC ROTL ROTR ROUND RTE RTFI RTS RTSD
+%token SAT SATR SBB SCCND SCMPU SETPSW SHAR SHLL SHLR SMOVB SMOVF
+%token SMOVU SSTR STNZ STOP STZ SUB SUNTIL SWHILE
+%token TST
+%token WAIT
+%token XCHG XOR
+
+%%
+/* ====================================================================== */
+
+statement :
+
+ UNKNOWN_OPCODE
+ { as_bad (_("Unknown opcode: %s"), rx_init_start); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BRK
+ { B1 (0x00); }
+
+ | DBT
+ { B1 (0x01); }
+
+ | RTS
+ { B1 (0x02); }
+
+ | NOP
+ { B1 (0x03); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BRA EXPR
+ { if (rx_disp3op ($2))
+ { B1 (0x08); rx_disp3 ($2, 5); }
+ else if (rx_intop ($2, 8))
+ { B1 (0x2e); PC1 ($2); }
+ else if (rx_intop ($2, 16))
+ { B1 (0x38); PC2 ($2); }
+ else if (rx_intop ($2, 24))
+ { B1 (0x04); PC3 ($2); }
+ else
+ { rx_relax (RX_RELAX_BRANCH, 0);
+ rx_linkrelax_branch ();
+ /* We'll convert this to a longer one later if needed. */
+ B1 (0x08); rx_disp3 ($2, 5); } }
+
+ | BRA DOT_A EXPR
+ { B1 (0x04); PC3 ($3); }
+
+ | BRA DOT_S EXPR
+ { B1 (0x08); rx_disp3 ($3, 5); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BSR EXPR
+ { if (rx_intop ($2, 16))
+ { B1 (0x39); PC2 ($2); }
+ else if (rx_intop ($2, 24))
+ { B1 (0x05); PC3 ($2); }
+ else
+ { rx_relax (RX_RELAX_BRANCH, 0);
+ rx_linkrelax_branch ();
+ B1 (0x39); PC2 ($2); } }
+ | BSR DOT_A EXPR
+ { B1 (0x05), PC3 ($3); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BCND DOT_S EXPR
+ { if ($1 == COND_EQ || $1 == COND_NE)
+ { B1 ($1 == COND_EQ ? 0x10 : 0x18); rx_disp3 ($3, 5); }
+ else
+ as_bad (_("Only BEQ and BNE may have .S")); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BCND DOT_B EXPR
+ { B1 (0x20); F ($1, 4, 4); PC1 ($3); }
+
+ | BRA DOT_B EXPR
+ { B1 (0x2e), PC1 ($3); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BRA DOT_W EXPR
+ { B1 (0x38), PC2 ($3); }
+ | BSR DOT_W EXPR
+ { B1 (0x39), PC2 ($3); }
+ | BCND DOT_W EXPR
+ { if ($1 == COND_EQ || $1 == COND_NE)
+ { B1 ($1 == COND_EQ ? 0x3a : 0x3b); PC2 ($3); }
+ else
+ as_bad (_("Only BEQ and BNE may have .W")); }
+ | BCND EXPR
+ { if ($1 == COND_EQ || $1 == COND_NE)
+ {
+ rx_relax (RX_RELAX_BRANCH, 0);
+ rx_linkrelax_branch ();
+ B1 ($1 == COND_EQ ? 0x10 : 0x18); rx_disp3 ($2, 5);
+ }
+ else
+ {
+ rx_relax (RX_RELAX_BRANCH, 0);
+ /* This is because we might turn it into a
+ jump-over-jump long branch. */
+ rx_linkrelax_branch ();
+ B1 (0x20); F ($1, 4, 4); PC1 ($2);
+ } }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV DOT_B '#' EXPR ',' disp '[' REG ']'
+ /* rx_disp5op changes the value if it succeeds, so keep it last. */
+ { if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, BSIZE))
+ { B2 (0x3c, 0); rx_field5s2 ($6); F ($8, 9, 3); O1 ($4); }
+ else
+ { B2 (0xf8, 0x04); F ($8, 8, 4); DSP ($6, 6, BSIZE); O1 ($4);
+ if ($4.X_op != O_constant && $4.X_op != O_big) rx_linkrelax_imm (12); } }
+
+ | MOV DOT_W '#' EXPR ',' disp '[' REG ']'
+ { 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); } }
+
+ | MOV DOT_L '#' EXPR ',' disp '[' REG ']'
+ { if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, LSIZE))
+ { B2 (0x3e, 0); rx_field5s2 ($6); F ($8, 9, 3); O1 ($4); }
+ else
+ { B2 (0xf8, 0x02); F ($8, 8, 4); DSP ($6, 6, LSIZE); IMM ($4, 12); } }
+
+/* ---------------------------------------------------------------------- */
+
+ | RTSD '#' EXPR ',' REG '-' REG
+ { B2 (0x3f, 0); F ($5, 8, 4); F ($7, 12, 4); rtsd_immediate ($3);
+ if ($5 == 0)
+ rx_error (_("RTSD cannot pop R0"));
+ if ($5 > $7)
+ rx_error (_("RTSD first reg must be <= second reg")); }
+
+/* ---------------------------------------------------------------------- */
+
+ | CMP REG ',' REG
+ { B2 (0x47, 0); F ($2, 8, 4); F ($4, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | CMP disp '[' REG ']' DOT_UB ',' REG
+ { B2 (0x44, 0); F ($4, 8, 4); F ($8, 12, 4); DSP ($2, 6, BSIZE); }
+
+ | CMP disp '[' REG ']' memex ',' REG
+ { B3 (MEMEX, 0x04, 0); F ($6, 8, 2); F ($4, 16, 4); F ($8, 20, 4); DSP ($2, 14, sizemap[$6]); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOVU bw REG ',' REG
+ { B2 (0x5b, 0x00); F ($2, 5, 1); F ($3, 8, 4); F ($5, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOVU bw '[' REG ']' ',' REG
+ { B2 (0x58, 0x00); F ($2, 5, 1); F ($4, 8, 4); F ($7, 12, 4); }
+
+ | MOVU bw EXPR '[' REG ']' ',' REG
+ { if ($5 <= 7 && $8 <= 7 && rx_disp5op (&$3, $2))
+ { B2 (0xb0, 0); F ($2, 4, 1); F ($5, 9, 3); F ($8, 13, 3); rx_field5s ($3); }
+ else
+ { B2 (0x58, 0x00); F ($2, 5, 1); F ($5, 8, 4); F ($8, 12, 4); DSP ($3, 6, $2); } }
+
+/* ---------------------------------------------------------------------- */
+
+ | SUB '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { 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); } } /* ? */
+
+ | CMP '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { B2 (0x61, 0); FE ($3, 8, 4); F ($5, 12, 4); }
+ else if (rx_uintop ($3, 8))
+ { B2 (0x75, 0x50); F ($5, 12, 4); UO1 ($3); }
+ else
+ { B2 (0x74, 0x00); F ($5, 12, 4); IMM ($3, 6); } }
+
+ | ADD '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { B2 (0x62, 0); FE ($3, 8, 4); F ($5, 12, 4); }
+ else
+ { B2 (0x70, 0); F ($5, 8, 4); F ($5, 12, 4); IMM ($3, 6); } }
+
+ | MUL '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { B2 (0x63, 0); FE ($3, 8, 4); F ($5, 12, 4); }
+ else
+ { B2 (0x74, 0x10); F ($5, 12, 4); IMM ($3, 6); } }
+
+ | AND_ '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { B2 (0x64, 0); FE ($3, 8, 4); F ($5, 12, 4); }
+ else
+ { B2 (0x74, 0x20); F ($5, 12, 4); IMM ($3, 6); } }
+
+ | OR '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { B2 (0x65, 0); FE ($3, 8, 4); F ($5, 12, 4); }
+ else
+ { B2 (0x74, 0x30); F ($5, 12, 4); IMM ($3, 6); } }
+
+ | MOV DOT_L '#' EXPR ',' REG
+ { if (rx_uintop ($4, 4))
+ { B2 (0x66, 0); FE ($4, 8, 4); F ($6, 12, 4); }
+ else if (rx_uintop ($4, 8))
+ { B2 (0x75, 0x40); F ($6, 12, 4); UO1 ($4); }
+ else
+ { B2 (0xfb, 0x02); F ($6, 8, 4); IMM ($4, 12); } }
+
+ | MOV '#' EXPR ',' REG
+ { if (rx_uintop ($3, 4))
+ { B2 (0x66, 0); FE ($3, 8, 4); F ($5, 12, 4); }
+ else if (rx_uintop ($3, 8))
+ { B2 (0x75, 0x40); F ($5, 12, 4); UO1 ($3); }
+ else
+ { B2 (0xfb, 0x02); F ($5, 8, 4); IMM ($3, 12); } }
+
+/* ---------------------------------------------------------------------- */
+
+ | RTSD '#' EXPR
+ { B1 (0x67); rtsd_immediate ($3); }
+
+/* ---------------------------------------------------------------------- */
+
+ | SHLR { sub_op = 0; } op_shift
+ | SHAR { sub_op = 1; } op_shift
+ | SHLL { sub_op = 2; } op_shift
+
+/* ---------------------------------------------------------------------- */
+
+ | PUSHM REG '-' REG
+ {
+ if ($2 == $4)
+ { B2 (0x7e, 0x80); F (LSIZE, 10, 2); F ($2, 12, 4); }
+ else
+ { B2 (0x6e, 0); F ($2, 8, 4); F ($4, 12, 4); }
+ if ($2 == 0)
+ rx_error (_("PUSHM cannot push R0"));
+ if ($2 > $4)
+ rx_error (_("PUSHM first reg must be <= second reg")); }
+
+/* ---------------------------------------------------------------------- */
+
+ | POPM REG '-' REG
+ {
+ if ($2 == $4)
+ { B2 (0x7e, 0xb0); F ($2, 12, 4); }
+ else
+ { B2 (0x6f, 0); F ($2, 8, 4); F ($4, 12, 4); }
+ if ($2 == 0)
+ rx_error (_("POPM cannot pop R0"));
+ if ($2 > $4)
+ rx_error (_("POPM first reg must be <= second reg")); }
+
+/* ---------------------------------------------------------------------- */
+
+ | ADD '#' EXPR ',' REG ',' REG
+ { B2 (0x70, 0x00); F ($5, 8, 4); F ($7, 12, 4); IMM ($3, 6); }
+
+/* ---------------------------------------------------------------------- */
+
+ | INT '#' EXPR
+ { B2(0x75, 0x60), UO1 ($3); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BSET '#' EXPR ',' REG
+ { B2 (0x78, 0); FE ($3, 7, 5); F ($5, 12, 4); }
+ | BCLR '#' EXPR ',' REG
+ { B2 (0x7a, 0); FE ($3, 7, 5); F ($5, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BTST '#' EXPR ',' REG
+ { B2 (0x7c, 0x00); FE ($3, 7, 5); F ($5, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | SAT REG
+ { B2 (0x7e, 0x30); F ($2, 12, 4); }
+ | RORC REG
+ { B2 (0x7e, 0x40); F ($2, 12, 4); }
+ | ROLC REG
+ { B2 (0x7e, 0x50); F ($2, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | PUSH bwl REG
+ { B2 (0x7e, 0x80); F ($2, 10, 2); F ($3, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | POP REG
+ { B2 (0x7e, 0xb0); F ($2, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | PUSHC CREG
+ { if ($2 < 16)
+ { B2 (0x7e, 0xc0); F ($2, 12, 4); }
+ else
+ as_bad (_("PUSHC can only push the first 16 control registers")); }
+
+/* ---------------------------------------------------------------------- */
+
+ | POPC CREG
+ { if ($2 < 16)
+ { B2 (0x7e, 0xe0); F ($2, 12, 4); }
+ else
+ as_bad (_("POPC can only pop the first 16 control registers")); }
+
+/* ---------------------------------------------------------------------- */
+
+ | SETPSW flag
+ { B2 (0x7f, 0xa0); F ($2, 12, 4); }
+ | CLRPSW flag
+ { B2 (0x7f, 0xb0); F ($2, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | JMP REG
+ { B2 (0x7f, 0x00); F ($2, 12, 4); }
+ | JSR REG
+ { B2 (0x7f, 0x10); F ($2, 12, 4); }
+ | BRA opt_l REG
+ { B2 (0x7f, 0x40); F ($3, 12, 4); }
+ | BSR opt_l REG
+ { B2 (0x7f, 0x50); F ($3, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | SCMPU
+ { B2 (0x7f, 0x83); }
+ | SMOVU
+ { B2 (0x7f, 0x87); }
+ | SMOVB
+ { B2 (0x7f, 0x8b); }
+ | SMOVF
+ { B2 (0x7f, 0x8f); }
+
+/* ---------------------------------------------------------------------- */
+
+ | SUNTIL bwl
+ { B2 (0x7f, 0x80); F ($2, 14, 2); }
+ | SWHILE bwl
+ { B2 (0x7f, 0x84); F ($2, 14, 2); }
+ | SSTR bwl
+ { B2 (0x7f, 0x88); F ($2, 14, 2); }
+
+/* ---------------------------------------------------------------------- */
+
+ | RMPA bwl
+ { B2 (0x7f, 0x8c); F ($2, 14, 2); }
+
+/* ---------------------------------------------------------------------- */
+
+ | RTFI
+ { B2 (0x7f, 0x94); }
+ | RTE
+ { B2 (0x7f, 0x95); }
+ | WAIT
+ { B2 (0x7f, 0x96); }
+ | SATR
+ { B2 (0x7f, 0x93); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MVTIPL '#' EXPR
+ { B2 (0x7f, 0x98); FE ($3, 13, 3); }
+
+/* ---------------------------------------------------------------------- */
+
+ /* rx_disp5op changes the value if it succeeds, so keep it last. */
+ | MOV bwl REG ',' EXPR '[' REG ']'
+ { if ($3 <= 7 && $7 <= 7 && rx_disp5op (&$5, $2))
+ { B2 (0x80, 0); F ($2, 2, 2); F ($7, 9, 3); F ($3, 13, 3); rx_field5s ($5); }
+ else
+ { B2 (0xc3, 0x00); F ($2, 2, 2); F ($7, 8, 4); F ($3, 12, 4); DSP ($5, 4, $2); }}
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl EXPR '[' REG ']' ',' REG
+ { if ($5 <= 7 && $8 <= 7 && rx_disp5op (&$3, $2))
+ { B2 (0x88, 0); F ($2, 2, 2); F ($5, 9, 3); F ($8, 13, 3); rx_field5s ($3); }
+ else
+ { B2 (0xcc, 0x00); F ($2, 2, 2); F ($5, 8, 4); F ($8, 12, 4); DSP ($3, 6, $2); } }
+
+/* ---------------------------------------------------------------------- */
+
+ /* MOV a,b - if a is a reg and b is mem, src and dest are
+ swapped. */
+
+ /* We don't use "disp" here because it causes a shift/reduce
+ conflict with the other displacement-less patterns. */
+
+ | MOV bwl REG ',' '[' REG ']'
+ { B2 (0xc3, 0x00); F ($2, 2, 2); F ($6, 8, 4); F ($3, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl '[' REG ']' ',' disp '[' REG ']'
+ { B2 (0xc0, 0); F ($2, 2, 2); F ($4, 8, 4); F ($9, 12, 4); DSP ($7, 4, $2); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl EXPR '[' REG ']' ',' disp '[' REG ']'
+ { B2 (0xc0, 0x00); F ($2, 2, 2); F ($5, 8, 4); F ($10, 12, 4); DSP ($3, 6, $2); DSP ($8, 4, $2); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl REG ',' REG
+ { B2 (0xcf, 0x00); F ($2, 2, 2); F ($3, 8, 4); F ($5, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl '[' REG ']' ',' REG
+ { B2 (0xcc, 0x00); F ($2, 2, 2); F ($4, 8, 4); F ($7, 12, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BSET '#' EXPR ',' disp '[' REG ']' DOT_B
+ { B2 (0xf0, 0x00); F ($7, 8, 4); FE ($3, 13, 3); DSP ($5, 6, BSIZE); }
+ | BCLR '#' EXPR ',' disp '[' REG ']' DOT_B
+ { B2 (0xf0, 0x08); F ($7, 8, 4); FE ($3, 13, 3); DSP ($5, 6, BSIZE); }
+ | BTST '#' EXPR ',' disp '[' REG ']' DOT_B
+ { B2 (0xf4, 0x00); F ($7, 8, 4); FE ($3, 13, 3); DSP ($5, 6, BSIZE); }
+
+/* ---------------------------------------------------------------------- */
+
+ | PUSH bwl disp '[' REG ']'
+ { B2 (0xf4, 0x08); F ($2, 14, 2); F ($5, 8, 4); DSP ($3, 6, $2); }
+
+/* ---------------------------------------------------------------------- */
+
+ | 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
+ | MAX { sub_op = 4; } op_dp20_rim
+ | MIN { sub_op = 5; } op_dp20_rim
+ | EMUL { sub_op = 6; } op_dp20_i
+ | EMULU { sub_op = 7; } op_dp20_i
+ | DIV { sub_op = 8; } op_dp20_rim
+ | 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
+ | STZ { sub_op = 14; } op_dp20_i
+ | STNZ { sub_op = 15; } op_dp20_i
+
+/* ---------------------------------------------------------------------- */
+
+ | EMUL { sub_op = 6; } op_xchg
+ | EMULU { sub_op = 7; } op_xchg
+ | XCHG { sub_op = 16; } op_xchg
+ | ITOF { sub_op = 17; } op_xchg
+
+/* ---------------------------------------------------------------------- */
+
+ | BSET REG ',' REG
+ { id24 (1, 0x63, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
+ | BCLR REG ',' REG
+ { id24 (1, 0x67, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
+ | BTST REG ',' REG
+ { id24 (1, 0x6b, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
+ | BNOT REG ',' REG
+ { id24 (1, 0x6f, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
+
+ | BSET REG ',' disp '[' REG ']' DOT_B
+ { id24 (1, 0x60, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
+ | BCLR REG ',' disp '[' REG ']' DOT_B
+ { id24 (1, 0x64, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
+ | BTST REG ',' disp '[' REG ']' DOT_B
+ { id24 (1, 0x68, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
+ | BNOT REG ',' disp '[' REG ']' DOT_B
+ { id24 (1, 0x6c, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
+
+/* ---------------------------------------------------------------------- */
+
+ | FSUB { sub_op = 0; } float2_op
+ | FCMP { sub_op = 1; } float2_op
+ | FADD { sub_op = 2; } float2_op
+ | FMUL { sub_op = 3; } float2_op
+ | FDIV { sub_op = 4; } float2_op
+ | FTOI { sub_op = 5; } float2_op_ni
+ | ROUND { sub_op = 6; } float2_op_ni
+
+/* ---------------------------------------------------------------------- */
+
+ | SCCND DOT_L REG
+ { id24 (1, 0xdb, 0x00); F ($1, 20, 4); F ($3, 16, 4); }
+ | SCCND bwl disp '[' REG ']'
+ { id24 (1, 0xd0, 0x00); F ($1, 20, 4); F ($2, 12, 2); F ($5, 16, 4); DSP ($3, 14, $2); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BMCND '#' EXPR ',' disp '[' REG ']' DOT_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
+ { id24 (1, 0xe0, 0x0f); FE ($3, 11, 3); F ($7, 16, 4);
+ DSP ($5, 14, BSIZE); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MULHI REG ',' REG
+ { id24 (2, 0x00, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
+ | MULLO REG ',' REG
+ { id24 (2, 0x01, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
+ | MACHI REG ',' REG
+ { id24 (2, 0x04, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
+ | MACLO REG ',' REG
+ { id24 (2, 0x05, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ /* We don't have syntax for these yet. */
+ | MVTACHI REG
+ { id24 (2, 0x17, 0x00); F ($2, 20, 4); }
+ | MVTACLO REG
+ { id24 (2, 0x17, 0x10); F ($2, 20, 4); }
+ | MVFACHI REG
+ { id24 (2, 0x1f, 0x00); F ($2, 20, 4); }
+ | MVFACMI REG
+ { id24 (2, 0x1f, 0x20); F ($2, 20, 4); }
+ | MVFACLO REG
+ { id24 (2, 0x1f, 0x10); F ($2, 20, 4); }
+
+ | RACW '#' EXPR
+ { id24 (2, 0x18, 0x00);
+ if (rx_uintop ($3, 4) && $3.X_add_number == 1)
+ ;
+ else if (rx_uintop ($3, 4) && $3.X_add_number == 2)
+ F (1, 19, 1);
+ else
+ as_bad (_("RACW expects #1 or #2"));}
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl REG ',' '[' REG '+' ']'
+ { id24 (2, 0x20, 0); F ($2, 14, 2); F ($6, 16, 4); F ($3, 20, 4); }
+ | MOV bwl REG ',' '[' '-' REG ']'
+ { id24 (2, 0x24, 0); F ($2, 14, 2); F ($7, 16, 4); F ($3, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl '[' REG '+' ']' ',' REG
+ { id24 (2, 0x28, 0); F ($2, 14, 2); F ($4, 16, 4); F ($8, 20, 4); }
+ | MOV bwl '[' '-' REG ']' ',' REG
+ { id24 (2, 0x2c, 0); F ($2, 14, 2); F ($5, 16, 4); F ($8, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOVU bw '[' REG '+' ']' ',' REG
+ { id24 (2, 0x38, 0); F ($2, 15, 1); F ($4, 16, 4); F ($8, 20, 4); }
+ | MOVU bw '[' '-' REG ']' ',' REG
+ { id24 (2, 0x3c, 0); F ($2, 15, 1); F ($5, 16, 4); F ($8, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | ROTL { sub_op = 6; } op_shift_rot
+ | ROTR { sub_op = 4; } op_shift_rot
+ | REVW { sub_op = 5; } op_shift_rot
+ | REVL { sub_op = 7; } op_shift_rot
+
+/* ---------------------------------------------------------------------- */
+
+ | MVTC REG ',' CREG
+ { id24 (2, 0x68, 0x00); F ($4 % 16, 20, 4); F ($4 / 16, 15, 1);
+ F ($2, 16, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MVFC CREG ',' REG
+ { id24 (2, 0x6a, 0); F ($2, 15, 5); F ($4, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | ROTL '#' EXPR ',' REG
+ { id24 (2, 0x6e, 0); FE ($3, 15, 5); F ($5, 20, 4); }
+ | ROTR '#' EXPR ',' REG
+ { id24 (2, 0x6c, 0); FE ($3, 15, 5); F ($5, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MVTC '#' EXPR ',' CREG
+ { id24 (2, 0x73, 0x00); F ($5, 19, 5); IMM ($3, 12); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BMCND '#' EXPR ',' REG
+ { id24 (2, 0xe0, 0x00); F ($1, 16, 4); FE ($3, 11, 5);
+ F ($5, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | BNOT '#' EXPR ',' REG
+ { id24 (2, 0xe0, 0xf0); FE ($3, 11, 5); F ($5, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | MOV bwl REG ',' '[' REG ',' REG ']'
+ { id24 (3, 0x00, 0); F ($2, 10, 2); F ($6, 12, 4); F ($8, 16, 4); F ($3, 20, 4); }
+
+ | MOV bwl '[' REG ',' REG ']' ',' REG
+ { id24 (3, 0x40, 0); F ($2, 10, 2); F ($4, 12, 4); F ($6, 16, 4); F ($9, 20, 4); }
+
+ | MOVU bw '[' REG ',' REG ']' ',' REG
+ { id24 (3, 0xc0, 0); F ($2, 10, 2); F ($4, 12, 4); F ($6, 16, 4); F ($9, 20, 4); }
+
+/* ---------------------------------------------------------------------- */
+
+ | SUB { sub_op = 0; } op_subadd
+ | ADD { sub_op = 2; } op_subadd
+ | MUL { sub_op = 3; } op_subadd
+ | AND_ { sub_op = 4; } op_subadd
+ | OR { sub_op = 5; } op_subadd
+
+/* ---------------------------------------------------------------------- */
+/* There is no SBB #imm so we fake it with ADC. */
+
+ | SBB '#' EXPR ',' REG
+ { id24 (2, 0x70, 0x20); F ($5, 20, 4); NBIMM ($3, 12); }
+
+/* ---------------------------------------------------------------------- */
+
+ ;
+
+/* ====================================================================== */
+
+op_subadd
+ : REG ',' REG
+ { B2 (0x43 + (sub_op<<2), 0); F ($1, 8, 4); F ($3, 12, 4); }
+ | disp '[' REG ']' DOT_UB ',' REG
+ { B2 (0x40 + (sub_op<<2), 0); F ($3, 8, 4); F ($7, 12, 4); DSP ($1, 6, BSIZE); }
+ | disp '[' REG ']' memex ',' REG
+ { B3 (MEMEX, sub_op<<2, 0); F ($5, 8, 2); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, sizemap[$5]); }
+ | REG ',' REG ',' REG
+ { id24 (4, sub_op<<4, 0), F ($5, 12, 4), F ($1, 16, 4), F ($3, 20, 4); }
+ ;
+
+/* sbb, 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); }
+ | disp '[' REG ']' DOT_UB ',' REG
+ { id24 (1, 0x00 + (sub_op<<2), 0x00); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, BSIZE); }
+ | disp '[' REG ']' memex ',' REG
+ { B4 (MEMEX, 0x20 + ($5 << 6), 0x00 + sub_op, 0x00);
+ F ($3, 24, 4); F ($7, 28, 4); DSP ($1, 14, sizemap[$5]); }
+ ;
+
+op_dp20_i
+ : '#' EXPR ',' REG
+ { id24 (2, 0x70, sub_op<<4); F ($4, 20, 4); IMM ($2, 12); }
+ ;
+
+op_dp20_rim
+ : op_dp20_rm
+ | op_dp20_i
+ ;
+
+op_dp20_rms
+ : op_dp20_rm
+ | REG
+ { B2 (0x7e, sub_op2 << 4); F ($1, 12, 4); }
+ ;
+
+/* xchg, itof, emul, emulu */
+op_xchg
+ : REG ',' REG
+ { id24 (1, 0x03 + (sub_op<<2), 0); F ($1, 16, 4); F ($3, 20, 4); }
+ | disp '[' REG ']' DOT_UB ',' REG
+ { id24 (1, 0x00 + (sub_op<<2), 0); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, BSIZE); }
+ | disp '[' REG ']' memex ',' REG
+ { B4 (MEMEX, 0x20, 0x00 + sub_op, 0); F ($5, 8, 2); F ($3, 24, 4); F ($7, 28, 4);
+ DSP ($1, 14, sizemap[$5]); }
+ ;
+
+/* 000:SHLR, 001:SHAR, 010:SHLL, 011:-, 100:ROTR, 101:REVW, 110:ROTL, 111:REVL */
+op_shift_rot
+ : REG ',' REG
+ { id24 (2, 0x60 + sub_op, 0); F ($1, 16, 4); F ($3, 20, 4); }
+ ;
+op_shift
+ : '#' EXPR ',' REG
+ { B2 (0x68 + (sub_op<<1), 0); FE ($2, 7, 5); F ($4, 12, 4); }
+ | '#' EXPR ',' REG ',' REG
+ { id24 (2, 0x80 + (sub_op << 5), 0); FE ($2, 11, 5); F ($4, 16, 4); F ($6, 20, 4); }
+ | op_shift_rot
+ ;
+
+
+
+float2_op
+ : '#' EXPR ',' REG
+ { id24 (2, 0x72, sub_op << 4); F ($4, 20, 4); O4 ($2); }
+ | 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); }
+ ;
+
+/* ====================================================================== */
+
+disp : { $$ = zero_expr (); }
+ | EXPR { $$ = $1; }
+ ;
+
+flag : { need_flag = 1; } FLAG { need_flag = 0; $$ = $2; }
+ ;
+
+/* DOT_UB is not listed here, it's handled with a separate pattern. */
+/* Use sizemap[$n] to get LSIZE etc. */
+memex : DOT_B { $$ = 0; }
+ | DOT_W { $$ = 1; }
+ | { $$ = 2; }
+ | DOT_L { $$ = 2; }
+ | DOT_UW { $$ = 3; }
+ ;
+
+bwl : { $$ = LSIZE; }
+ | DOT_B { $$ = BSIZE; }
+ | DOT_W { $$ = WSIZE; }
+ | DOT_L { $$ = LSIZE; }
+ ;
+
+bw : { $$ = 1; }
+ | DOT_B { $$ = 0; }
+ | DOT_W { $$ = 1; }
+ ;
+
+opt_l : {}
+ | DOT_L {}
+ ;
+
+%%
+/* ====================================================================== */
+
+static struct
+{
+ const char * string;
+ int token;
+ int val;
+}
+token_table[] =
+{
+ { "r0", REG, 0 },
+ { "r1", REG, 1 },
+ { "r2", REG, 2 },
+ { "r3", REG, 3 },
+ { "r4", REG, 4 },
+ { "r5", REG, 5 },
+ { "r6", REG, 6 },
+ { "r7", REG, 7 },
+ { "r8", REG, 8 },
+ { "r9", REG, 9 },
+ { "r10", REG, 10 },
+ { "r11", REG, 11 },
+ { "r12", REG, 12 },
+ { "r13", REG, 13 },
+ { "r14", REG, 14 },
+ { "r15", REG, 15 },
+
+ { "psw", CREG, 0 },
+ { "pc", CREG, 1 },
+ { "usp", CREG, 2 },
+ { "fpsw", CREG, 3 },
+ { "cpen", CREG, 4 },
+ /* reserved */
+ /* reserved */
+ { "wr", CREG, 7 },
+
+ { "bpsw", CREG, 8 },
+ { "bpc", CREG, 9 },
+ { "isp", CREG, 10 },
+ { "fintv", CREG, 11 },
+ { "intb", CREG, 12 },
+
+ { "pbp", CREG, 16 },
+ { "pben", CREG, 17 },
+
+ { "bbpsw", CREG, 24 },
+ { "bbpc", CREG, 25 },
+
+ { ".s", DOT_S, 0 },
+ { ".b", DOT_B, 0 },
+ { ".w", DOT_W, 0 },
+ { ".l", DOT_L, 0 },
+ { ".a", DOT_A , 0},
+ { ".ub", DOT_UB, 0 },
+ { ".uw", DOT_UW , 0},
+
+ { "c", FLAG, 0 },
+ { "z", FLAG, 1 },
+ { "s", FLAG, 2 },
+ { "o", FLAG, 3 },
+ { "i", FLAG, 8 },
+ { "u", FLAG, 9 },
+
+#define OPC(x) { #x, x, IS_OPCODE }
+ OPC(ABS),
+ OPC(ADC),
+ OPC(ADD),
+ { "and", AND_, IS_OPCODE },
+ OPC(BCLR),
+ OPC(BCND),
+ OPC(BMCND),
+ OPC(BNOT),
+ OPC(BRA),
+ OPC(BRK),
+ OPC(BSET),
+ OPC(BSR),
+ OPC(BTST),
+ OPC(CLRPSW),
+ OPC(CMP),
+ OPC(DBT),
+ OPC(DIV),
+ OPC(DIVU),
+ OPC(EDIV),
+ OPC(EDIVU),
+ OPC(EMUL),
+ OPC(EMULU),
+ OPC(FADD),
+ OPC(FCMP),
+ OPC(FDIV),
+ OPC(FMUL),
+ OPC(FREIT),
+ OPC(FSUB),
+ OPC(FTOI),
+ OPC(INT),
+ OPC(ITOF),
+ OPC(JMP),
+ OPC(JSR),
+ OPC(MVFACHI),
+ OPC(MVFACMI),
+ OPC(MVFACLO),
+ OPC(MVFC),
+ OPC(MVTACHI),
+ OPC(MVTACLO),
+ OPC(MVTC),
+ OPC(MVTIPL),
+ OPC(MACHI),
+ OPC(MACLO),
+ OPC(MAX),
+ OPC(MIN),
+ OPC(MOV),
+ OPC(MOVU),
+ OPC(MUL),
+ OPC(MULHI),
+ OPC(MULLO),
+ OPC(MULU),
+ OPC(NEG),
+ OPC(NOP),
+ OPC(NOT),
+ OPC(OR),
+ OPC(POP),
+ OPC(POPC),
+ OPC(POPM),
+ OPC(PUSH),
+ OPC(PUSHA),
+ OPC(PUSHC),
+ OPC(PUSHM),
+ OPC(RACW),
+ OPC(REIT),
+ OPC(REVL),
+ OPC(REVW),
+ OPC(RMPA),
+ OPC(ROLC),
+ OPC(RORC),
+ OPC(ROTL),
+ OPC(ROTR),
+ OPC(ROUND),
+ OPC(RTE),
+ OPC(RTFI),
+ OPC(RTS),
+ OPC(RTSD),
+ OPC(SAT),
+ OPC(SATR),
+ OPC(SBB),
+ OPC(SCCND),
+ OPC(SCMPU),
+ OPC(SETPSW),
+ OPC(SHAR),
+ OPC(SHLL),
+ OPC(SHLR),
+ OPC(SMOVB),
+ OPC(SMOVF),
+ OPC(SMOVU),
+ OPC(SSTR),
+ OPC(STNZ),
+ OPC(STOP),
+ OPC(STZ),
+ OPC(SUB),
+ OPC(SUNTIL),
+ OPC(SWHILE),
+ OPC(TST),
+ OPC(WAIT),
+ OPC(XCHG),
+ OPC(XOR),
+};
+
+#define NUM_TOKENS (sizeof (token_table) / sizeof (token_table[0]))
+
+static struct
+{
+ char * string;
+ int token;
+}
+condition_opcode_table[] =
+{
+ { "b", BCND },
+ { "bm", BMCND },
+ { "sc", SCCND },
+};
+
+#define NUM_CONDITION_OPCODES (sizeof (condition_opcode_table) / sizeof (condition_opcode_table[0]))
+
+static struct
+{
+ char * string;
+ int val;
+}
+condition_table[] =
+{
+ { "z", 0 },
+ { "eq", 0 },
+ { "geu", 2 },
+ { "c", 2 },
+ { "gtu", 4 },
+ { "pz", 6 },
+ { "ge", 8 },
+ { "gt", 10 },
+ { "o", 12},
+ /* always = 14 */
+ { "nz", 1 },
+ { "ne", 1 },
+ { "ltu", 3 },
+ { "nc", 3 },
+ { "leu", 5 },
+ { "n", 7 },
+ { "lt", 9 },
+ { "le", 11 },
+ { "no", 13 }
+ /* never = 15 */
+};
+
+#define NUM_CONDITIONS (sizeof (condition_table) / sizeof (condition_table[0]))
+
+void
+rx_lex_init (char * beginning, char * ending)
+{
+ rx_init_start = beginning;
+ rx_lex_start = beginning;
+ rx_lex_end = ending;
+ rx_in_brackets = 0;
+ rx_last_token = 0;
+
+ setbuf (stdout, 0);
+}
+
+static int
+check_condition (char * base)
+{
+ char * cp;
+ unsigned int i;
+
+ if ((unsigned) (rx_lex_end - rx_lex_start) < strlen (base) + 1)
+ return 0;
+ if (memcmp (rx_lex_start, base, strlen (base)))
+ return 0;
+ cp = rx_lex_start + strlen (base);
+ for (i = 0; i < NUM_CONDITIONS; i ++)
+ {
+ if (strcasecmp (cp, condition_table[i].string) == 0)
+ {
+ rx_lval.regno = condition_table[i].val;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+rx_lex (void)
+{
+ unsigned int ci;
+ char * save_input_pointer;
+
+ while (ISSPACE (*rx_lex_start)
+ && rx_lex_start != rx_lex_end)
+ rx_lex_start ++;
+
+ rx_last_exp_start = rx_lex_start;
+
+ if (rx_lex_start == rx_lex_end)
+ return 0;
+
+ if (ISALPHA (*rx_lex_start)
+ || (*rx_lex_start == '.' && ISALPHA (rx_lex_start[1])))
+ {
+ unsigned int i;
+ char * e;
+ char save;
+
+ for (e = rx_lex_start + 1;
+ e < rx_lex_end && ISALNUM (*e);
+ e ++)
+ ;
+ save = *e;
+ *e = 0;
+
+ if (rx_last_token == 0)
+ for (ci = 0; ci < NUM_CONDITION_OPCODES; ci ++)
+ if (check_condition (condition_opcode_table[ci].string))
+ {
+ *e = save;
+ rx_lex_start = e;
+ rx_last_token = condition_opcode_table[ci].token;
+ return condition_opcode_table[ci].token;
+ }
+
+ for (i = 0; i < NUM_TOKENS; i++)
+ if (strcasecmp (rx_lex_start, token_table[i].string) == 0
+ && !(token_table[i].val == IS_OPCODE && rx_last_token != 0)
+ && !(token_table[i].token == FLAG && !need_flag))
+ {
+ rx_lval.regno = token_table[i].val;
+ *e = save;
+ rx_lex_start = e;
+ rx_last_token = token_table[i].token;
+ return token_table[i].token;
+ }
+ *e = save;
+ }
+
+ if (rx_last_token == 0)
+ {
+ rx_last_token = UNKNOWN_OPCODE;
+ return UNKNOWN_OPCODE;
+ }
+
+ if (rx_last_token == UNKNOWN_OPCODE)
+ return 0;
+
+ if (*rx_lex_start == '[')
+ rx_in_brackets = 1;
+ if (*rx_lex_start == ']')
+ rx_in_brackets = 0;
+
+ if (rx_in_brackets
+ || rx_last_token == REG
+ || strchr ("[],#", *rx_lex_start))
+ {
+ rx_last_token = *rx_lex_start;
+ return *rx_lex_start ++;
+ }
+
+ save_input_pointer = input_line_pointer;
+ input_line_pointer = rx_lex_start;
+ rx_lval.exp.X_md = 0;
+ expression (&rx_lval.exp);
+
+ /* We parse but ignore any :<size> modifier on expressions. */
+ if (*input_line_pointer == ':')
+ {
+ char *cp;
+
+ for (cp = input_line_pointer + 1; *cp && cp < rx_lex_end; cp++)
+ if (!ISDIGIT (*cp))
+ break;
+ if (cp > input_line_pointer+1)
+ input_line_pointer = cp;
+ }
+
+ rx_lex_start = input_line_pointer;
+ input_line_pointer = save_input_pointer;
+ rx_last_token = EXPR;
+ return EXPR;
+}
+
+int
+rx_error (char * str)
+{
+ int len;
+
+ len = rx_last_exp_start - rx_init_start;
+
+ as_bad ("%s", rx_init_start);
+ as_bad ("%*s^ %s", len, "", str);
+ return 0;
+}
+
+static int
+rx_intop (expressionS exp, int nbits)
+{
+ long v;
+
+ if (exp.X_op == O_big && nbits == 32)
+ return 1;
+ if (exp.X_op != O_constant)
+ return 0;
+ v = exp.X_add_number;
+
+ switch (nbits)
+ {
+ case 4:
+ return -0x8 <= v && v <= 0x7;
+ case 5:
+ return -0x10 <= v && v <= 0x17;
+ case 8:
+ return -0x80 <= v && v <= 0x7f;
+ case 16:
+ return -0x8000 <= v && v <= 0x7fff;
+ case 24:
+ return -0x800000 <= v && v <= 0x7fffff;
+ case 32:
+ return 1;
+ default:
+ printf ("rx_intop passed %d\n", nbits);
+ abort ();
+ }
+ return 1;
+}
+
+static int
+rx_uintop (expressionS exp, int nbits)
+{
+ unsigned long v;
+
+ if (exp.X_op != O_constant)
+ return 0;
+ v = exp.X_add_number;
+
+ switch (nbits)
+ {
+ case 4:
+ return v <= 0xf;
+ case 8:
+ return v <= 0xff;
+ case 16:
+ return v <= 0xffff;
+ case 24:
+ return v <= 0xffffff;
+ default:
+ printf ("rx_uintop passed %d\n", nbits);
+ abort ();
+ }
+ return 1;
+}
+
+static int
+rx_disp3op (expressionS exp)
+{
+ unsigned long v;
+
+ if (exp.X_op != O_constant)
+ return 0;
+ v = exp.X_add_number;
+ if (v < 3 || v > 10)
+ return 0;
+ return 1;
+}
+
+static int
+rx_disp5op (expressionS * exp, int msize)
+{
+ long v;
+
+ if (exp->X_op != O_constant)
+ return 0;
+ v = exp->X_add_number;
+
+ switch (msize)
+ {
+ case BSIZE:
+ if (0 < v && v <= 31)
+ return 1;
+ break;
+ case WSIZE:
+ if (v & 1)
+ return 0;
+ if (0 < v && v <= 63)
+ {
+ exp->X_add_number >>= 1;
+ return 1;
+ }
+ break;
+ case LSIZE:
+ if (v & 3)
+ return 0;
+ if (0 < v && v <= 127)
+ {
+ exp->X_add_number >>= 2;
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Just like the above, but allows a zero displacement. */
+
+static int
+rx_disp5op0 (expressionS * exp, int msize)
+{
+ if (exp->X_op != O_constant)
+ return 0;
+ if (exp->X_add_number == 0)
+ return 1;
+ return rx_disp5op (exp, msize);
+}
+
+static int
+exp_val (expressionS exp)
+{
+ if (exp.X_op != O_constant)
+ {
+ rx_error (_("constant expected"));
+ return 0;
+ }
+ return exp.X_add_number;
+}
+
+static expressionS
+zero_expr (void)
+{
+ /* Static, so program load sets it to all zeros, which is what we want. */
+ static expressionS zero;
+ zero.X_op = O_constant;
+ return zero;
+}
+
+static int
+immediate (expressionS exp, int type, int pos)
+{
+ /* We will emit constants ourself here, so negate them. */
+ if (type == RXREL_NEGATIVE && exp.X_op == O_constant)
+ exp.X_add_number = - exp.X_add_number;
+ if (type == RXREL_NEGATIVE_BORROW)
+ {
+ if (exp.X_op == O_constant)
+ exp.X_add_number = - exp.X_add_number - 1;
+ else
+ rx_error (_("sbb cannot use symbolic immediates"));
+ }
+
+ if (rx_intop (exp, 8))
+ {
+ rx_op (exp, 1, type);
+ return 1;
+ }
+ else if (rx_intop (exp, 16))
+ {
+ rx_op (exp, 2, type);
+ return 2;
+ }
+ else if (rx_intop (exp, 24))
+ {
+ rx_op (exp, 3, type);
+ return 3;
+ }
+ else if (rx_intop (exp, 32))
+ {
+ rx_op (exp, 4, type);
+ return 0;
+ }
+ else if (type == RXREL_SIGNED)
+ {
+ /* This is a symbolic immediate, we will relax it later. */
+ rx_relax (RX_RELAX_IMM, pos);
+ rx_op (exp, linkrelax ? 4 : 1, type);
+ return 1;
+ }
+ else
+ {
+ /* Let the linker deal with it. */
+ rx_op (exp, 4, type);
+ return 0;
+ }
+}
+
+static int
+displacement (expressionS exp, int msize)
+{
+ int val;
+ int vshift = 0;
+
+ if (exp.X_op == O_symbol
+ && exp.X_md)
+ {
+ switch (exp.X_md)
+ {
+ case BFD_RELOC_GPREL16:
+ switch (msize)
+ {
+ case BSIZE:
+ exp.X_md = BFD_RELOC_RX_GPRELB;
+ break;
+ case WSIZE:
+ exp.X_md = BFD_RELOC_RX_GPRELW;
+ break;
+ case LSIZE:
+ exp.X_md = BFD_RELOC_RX_GPRELL;
+ break;
+ }
+ O2 (exp);
+ return 2;
+ }
+ }
+
+ if (exp.X_op != O_constant)
+ {
+ rx_error (_("displacements must be constants"));
+ return -1;
+ }
+ val = exp.X_add_number;
+
+ if (val == 0)
+ return 0;
+
+ switch (msize)
+ {
+ case BSIZE:
+ break;
+ case WSIZE:
+ if (val & 1)
+ rx_error (_("word displacement not word-aligned"));
+ vshift = 1;
+ break;
+ case LSIZE:
+ if (val & 3)
+ rx_error (_("long displacement not long-aligned"));
+ vshift = 2;
+ break;
+ default:
+ as_bad (_("displacement with unknown size (internal bug?)\n"));
+ break;
+ }
+
+ val >>= vshift;
+ exp.X_add_number = val;
+
+ if (0 <= val && val <= 255 )
+ {
+ O1 (exp);
+ return 1;
+ }
+
+ if (0 <= val && val <= 65535)
+ {
+ O2 (exp);
+ return 2;
+ }
+ if (val < 0)
+ rx_error (_("negative displacements not allowed"));
+ else
+ rx_error (_("displacement too large"));
+ return -1;
+}
+
+static void
+rtsd_immediate (expressionS exp)
+{
+ int val;
+
+ if (exp.X_op != O_constant)
+ {
+ rx_error (_("rtsd size must be constant"));
+ return;
+ }
+ val = exp.X_add_number;
+ if (val & 3)
+ rx_error (_("rtsd size must be multiple of 4"));
+
+ if (val < 0 || val > 1020)
+ rx_error (_("rtsd size must be 0..1020"));
+
+ val >>= 2;
+ exp.X_add_number = val;
+ O1 (exp);
+}