1 /* rx-parse.y Renesas RX parser
2 Copyright (C) 2008-2015 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
23 #include "safe-ctype.h"
26 static int rx_lex (void);
38 static int sizemap[] = { BSIZE, WSIZE, LSIZE, WSIZE };
40 /* Ok, here are the rules for using these macros...
42 B*() is used to specify the base opcode bytes. Fields to be filled
43 in later, leave zero. Call this first.
45 F() and FE() are used to fill in fields within the base opcode bytes. You MUST
46 call B*() before any F() or FE().
48 [UN]*O*(), PC*() appends operands to the end of the opcode. You
49 must call P() and B*() before any of these, so that the fixups
50 have the right byte location.
51 O = signed, UO = unsigned, NO = negated, PC = pcrel
53 IMM() adds an immediate and fills in the field for it.
54 NIMM() same, but negates the immediate.
55 NBIMM() same, but negates the immediate, for sbb.
56 DSP() adds a displacement, and fills in the field for it.
58 Note that order is significant for the O, IMM, and DSP macros, as
59 they append their data to the operand buffer in the order that you
62 Use "disp" for displacements whenever possible; this handles the
65 #define B1(b1) rx_base1 (b1)
66 #define B2(b1, b2) rx_base2 (b1, b2)
67 #define B3(b1, b2, b3) rx_base3 (b1, b2, b3)
68 #define B4(b1, b2, b3, b4) rx_base4 (b1, b2, b3, b4)
70 /* POS is bits from the MSB of the first byte to the LSB of the last byte. */
71 #define F(val,pos,sz) rx_field (val, pos, sz)
72 #define FE(exp,pos,sz) rx_field (exp_val (exp), pos, sz);
74 #define O1(v) rx_op (v, 1, RXREL_SIGNED); rx_range (v, -128, 255)
75 #define O2(v) rx_op (v, 2, RXREL_SIGNED); rx_range (v, -32768, 65536)
76 #define O3(v) rx_op (v, 3, RXREL_SIGNED); rx_range (v, -8388608, 16777216)
77 #define O4(v) rx_op (v, 4, RXREL_SIGNED)
79 #define UO1(v) rx_op (v, 1, RXREL_UNSIGNED); rx_range (v, 0, 255)
80 #define UO2(v) rx_op (v, 2, RXREL_UNSIGNED); rx_range (v, 0, 65536)
81 #define UO3(v) rx_op (v, 3, RXREL_UNSIGNED); rx_range (v, 0, 16777216)
82 #define UO4(v) rx_op (v, 4, RXREL_UNSIGNED)
84 #define NO1(v) rx_op (v, 1, RXREL_NEGATIVE)
85 #define NO2(v) rx_op (v, 2, RXREL_NEGATIVE)
86 #define NO3(v) rx_op (v, 3, RXREL_NEGATIVE)
87 #define NO4(v) rx_op (v, 4, RXREL_NEGATIVE)
89 #define PC1(v) rx_op (v, 1, RXREL_PCREL)
90 #define PC2(v) rx_op (v, 2, RXREL_PCREL)
91 #define PC3(v) rx_op (v, 3, RXREL_PCREL)
93 #define IMM_(v,pos,size) F (immediate (v, RXREL_SIGNED, pos, size), pos, 2); \
94 if (v.X_op != O_constant && v.X_op != O_big) rx_linkrelax_imm (pos)
95 #define IMM(v,pos) IMM_ (v, pos, 32)
96 #define IMMW(v,pos) IMM_ (v, pos, 16); rx_range (v, -32768, 65536)
97 #define IMMB(v,pos) IMM_ (v, pos, 8); rx_range (v, -128, 255)
98 #define NIMM(v,pos) F (immediate (v, RXREL_NEGATIVE, pos, 32), pos, 2)
99 #define NBIMM(v,pos) F (immediate (v, RXREL_NEGATIVE_BORROW, pos, 32), pos, 2)
100 #define DSP(v,pos,msz) if (!v.X_md) rx_relax (RX_RELAX_DISP, pos); \
101 else rx_linkrelax_dsp (pos); \
102 F (displacement (v, msz), pos, 2)
104 #define id24(a,b2,b3) B3 (0xfb+a, b2, b3)
106 static void rx_check_float_support (void);
107 static int rx_intop (expressionS, int, int);
108 static int rx_uintop (expressionS, int);
109 static int rx_disp3op (expressionS);
110 static int rx_disp5op (expressionS *, int);
111 static int rx_disp5op0 (expressionS *, int);
112 static int exp_val (expressionS exp);
113 static expressionS zero_expr (void);
114 static int immediate (expressionS, int, int, int);
115 static int displacement (expressionS, int);
116 static void rtsd_immediate (expressionS);
117 static void rx_range (expressionS, int, int);
119 static int need_flag = 0;
120 static int rx_in_brackets = 0;
121 static int rx_last_token = 0;
122 static char * rx_init_start;
123 static char * rx_last_exp_start = 0;
128 #define YYERROR_VERBOSE 1
139 %type <regno> REG FLAG CREG BCND BMCND SCCND
140 %type <regno> flag bwl bw memex
141 %type <exp> EXPR disp
145 %token EXPR UNKNOWN_OPCODE IS_OPCODE
147 %token DOT_S DOT_B DOT_W DOT_L DOT_A DOT_UB DOT_UW
149 %token ABS ADC ADD AND_
150 %token BCLR BCND BMCND BNOT BRA BRK BSET BSR BTST
153 %token EDIV EDIVU EMUL EMULU
154 %token FADD FCMP FDIV FMUL FREIT FSUB FTOI
157 %token MACHI MACLO MAX MIN MOV MOVU MUL MULHI MULLO MULU MVFACHI MVFACMI MVFACLO
158 %token MVFC MVTACHI MVTACLO MVTC MVTIPL
161 %token POP POPC POPM PUSH PUSHA PUSHC PUSHM
162 %token RACW REIT REVL REVW RMPA ROLC RORC ROTL ROTR ROUND RTE RTFI RTS RTSD
163 %token SAT SATR SBB SCCND SCMPU SETPSW SHAR SHLL SHLR SMOVB SMOVF
164 %token SMOVU SSTR STNZ STOP STZ SUB SUNTIL SWHILE
170 /* ====================================================================== */
175 { as_bad (_("Unknown opcode: %s"), rx_init_start); }
177 /* ---------------------------------------------------------------------- */
191 /* ---------------------------------------------------------------------- */
194 { if (rx_disp3op ($2))
195 { B1 (0x08); rx_disp3 ($2, 5); }
196 else if (rx_intop ($2, 8, 8))
197 { B1 (0x2e); PC1 ($2); }
198 else if (rx_intop ($2, 16, 16))
199 { B1 (0x38); PC2 ($2); }
200 else if (rx_intop ($2, 24, 24))
201 { B1 (0x04); PC3 ($2); }
203 { rx_relax (RX_RELAX_BRANCH, 0);
204 rx_linkrelax_branch ();
205 /* We'll convert this to a longer one later if needed. */
206 B1 (0x08); rx_disp3 ($2, 5); } }
209 { B1 (0x04); PC3 ($3); }
212 { B1 (0x08); rx_disp3 ($3, 5); }
214 /* ---------------------------------------------------------------------- */
217 { if (rx_intop ($2, 16, 16))
218 { B1 (0x39); PC2 ($2); }
219 else if (rx_intop ($2, 24, 24))
220 { B1 (0x05); PC3 ($2); }
222 { rx_relax (RX_RELAX_BRANCH, 0);
223 rx_linkrelax_branch ();
224 B1 (0x39); PC2 ($2); } }
226 { B1 (0x05), PC3 ($3); }
228 /* ---------------------------------------------------------------------- */
231 { if ($1 == COND_EQ || $1 == COND_NE)
232 { B1 ($1 == COND_EQ ? 0x10 : 0x18); rx_disp3 ($3, 5); }
234 as_bad (_("Only BEQ and BNE may have .S")); }
236 /* ---------------------------------------------------------------------- */
239 { B1 (0x20); F ($1, 4, 4); PC1 ($3); }
242 { B1 (0x2e), PC1 ($3); }
244 /* ---------------------------------------------------------------------- */
247 { B1 (0x38), PC2 ($3); }
249 { B1 (0x39), PC2 ($3); }
251 { if ($1 == COND_EQ || $1 == COND_NE)
252 { B1 ($1 == COND_EQ ? 0x3a : 0x3b); PC2 ($3); }
254 as_bad (_("Only BEQ and BNE may have .W")); }
256 { if ($1 == COND_EQ || $1 == COND_NE)
258 rx_relax (RX_RELAX_BRANCH, 0);
259 rx_linkrelax_branch ();
260 B1 ($1 == COND_EQ ? 0x10 : 0x18); rx_disp3 ($2, 5);
264 rx_relax (RX_RELAX_BRANCH, 0);
265 /* This is because we might turn it into a
266 jump-over-jump long branch. */
267 rx_linkrelax_branch ();
268 B1 (0x20); F ($1, 4, 4); PC1 ($2);
271 /* ---------------------------------------------------------------------- */
273 | MOV DOT_B '#' EXPR ',' disp '[' REG ']'
274 /* rx_disp5op changes the value if it succeeds, so keep it last. */
275 { if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, BSIZE))
276 { B2 (0x3c, 0); rx_field5s2 ($6); F ($8, 9, 3); O1 ($4); }
278 { B2 (0xf8, 0x04); F ($8, 8, 4); DSP ($6, 6, BSIZE); O1 ($4);
279 if ($4.X_op != O_constant && $4.X_op != O_big) rx_linkrelax_imm (12); } }
281 | MOV DOT_W '#' EXPR ',' disp '[' REG ']'
282 { if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, WSIZE))
283 { B2 (0x3d, 0); rx_field5s2 ($6); F ($8, 9, 3); O1 ($4); }
285 { B2 (0xf8, 0x01); F ($8, 8, 4); DSP ($6, 6, WSIZE); IMMW ($4, 12); } }
287 | MOV DOT_L '#' EXPR ',' disp '[' REG ']'
288 { if ($8 <= 7 && rx_uintop ($4, 8) && rx_disp5op0 (&$6, LSIZE))
289 { B2 (0x3e, 0); rx_field5s2 ($6); F ($8, 9, 3); O1 ($4); }
291 { B2 (0xf8, 0x02); F ($8, 8, 4); DSP ($6, 6, LSIZE); IMM ($4, 12); } }
293 /* ---------------------------------------------------------------------- */
295 | RTSD '#' EXPR ',' REG '-' REG
296 { B2 (0x3f, 0); F ($5, 8, 4); F ($7, 12, 4); rtsd_immediate ($3);
298 rx_error (_("RTSD cannot pop R0"));
300 rx_error (_("RTSD first reg must be <= second reg")); }
302 /* ---------------------------------------------------------------------- */
305 { B2 (0x47, 0); F ($2, 8, 4); F ($4, 12, 4); }
307 /* ---------------------------------------------------------------------- */
309 | CMP disp '[' REG ']' DOT_UB ',' REG
310 { B2 (0x44, 0); F ($4, 8, 4); F ($8, 12, 4); DSP ($2, 6, BSIZE); }
312 | CMP disp '[' REG ']' memex ',' REG
313 { B3 (MEMEX, 0x04, 0); F ($6, 8, 2); F ($4, 16, 4); F ($8, 20, 4); DSP ($2, 14, sizemap[$6]); }
315 /* ---------------------------------------------------------------------- */
317 | MOVU bw REG ',' REG
318 { B2 (0x5b, 0x00); F ($2, 5, 1); F ($3, 8, 4); F ($5, 12, 4); }
320 /* ---------------------------------------------------------------------- */
322 | MOVU bw '[' REG ']' ',' REG
323 { B2 (0x58, 0x00); F ($2, 5, 1); F ($4, 8, 4); F ($7, 12, 4); }
325 | MOVU bw EXPR '[' REG ']' ',' REG
326 { if ($5 <= 7 && $8 <= 7 && rx_disp5op (&$3, $2))
327 { B2 (0xb0, 0); F ($2, 4, 1); F ($5, 9, 3); F ($8, 13, 3); rx_field5s ($3); }
329 { B2 (0x58, 0x00); F ($2, 5, 1); F ($5, 8, 4); F ($8, 12, 4); DSP ($3, 6, $2); } }
331 /* ---------------------------------------------------------------------- */
333 | SUB '#' EXPR ',' REG
334 { if (rx_uintop ($3, 4))
335 { B2 (0x60, 0); FE ($3, 8, 4); F ($5, 12, 4); }
337 /* This is really an add, but we negate the immediate. */
338 { B2 (0x70, 0); F ($5, 8, 4); F ($5, 12, 4); NIMM ($3, 6); } }
340 | CMP '#' EXPR ',' REG
341 { if (rx_uintop ($3, 4))
342 { B2 (0x61, 0); FE ($3, 8, 4); F ($5, 12, 4); }
343 else if (rx_uintop ($3, 8))
344 { B2 (0x75, 0x50); F ($5, 12, 4); UO1 ($3); }
346 { B2 (0x74, 0x00); F ($5, 12, 4); IMM ($3, 6); } }
348 | ADD '#' EXPR ',' REG
349 { if (rx_uintop ($3, 4))
350 { B2 (0x62, 0); FE ($3, 8, 4); F ($5, 12, 4); }
352 { B2 (0x70, 0); F ($5, 8, 4); F ($5, 12, 4); IMM ($3, 6); } }
354 | MUL '#' EXPR ',' REG
355 { if (rx_uintop ($3, 4))
356 { B2 (0x63, 0); FE ($3, 8, 4); F ($5, 12, 4); }
358 { B2 (0x74, 0x10); F ($5, 12, 4); IMM ($3, 6); } }
360 | AND_ '#' EXPR ',' REG
361 { if (rx_uintop ($3, 4))
362 { B2 (0x64, 0); FE ($3, 8, 4); F ($5, 12, 4); }
364 { B2 (0x74, 0x20); F ($5, 12, 4); IMM ($3, 6); } }
366 | OR '#' EXPR ',' REG
367 { if (rx_uintop ($3, 4))
368 { B2 (0x65, 0); FE ($3, 8, 4); F ($5, 12, 4); }
370 { B2 (0x74, 0x30); F ($5, 12, 4); IMM ($3, 6); } }
372 | MOV DOT_L '#' EXPR ',' REG
373 { if (rx_uintop ($4, 4))
374 { B2 (0x66, 0); FE ($4, 8, 4); F ($6, 12, 4); }
375 else if (rx_uintop ($4, 8))
376 { B2 (0x75, 0x40); F ($6, 12, 4); UO1 ($4); }
378 { B2 (0xfb, 0x02); F ($6, 8, 4); IMM ($4, 12); } }
380 | MOV '#' EXPR ',' REG
381 { if (rx_uintop ($3, 4))
382 { B2 (0x66, 0); FE ($3, 8, 4); F ($5, 12, 4); }
383 else if (rx_uintop ($3, 8))
384 { B2 (0x75, 0x40); F ($5, 12, 4); UO1 ($3); }
386 { B2 (0xfb, 0x02); F ($5, 8, 4); IMM ($3, 12); } }
388 /* ---------------------------------------------------------------------- */
391 { B1 (0x67); rtsd_immediate ($3); }
393 /* ---------------------------------------------------------------------- */
395 | SHLR { sub_op = 0; } op_shift
396 | SHAR { sub_op = 1; } op_shift
397 | SHLL { sub_op = 2; } op_shift
399 /* ---------------------------------------------------------------------- */
404 { B2 (0x7e, 0x80); F (LSIZE, 10, 2); F ($2, 12, 4); }
406 { B2 (0x6e, 0); F ($2, 8, 4); F ($4, 12, 4); }
408 rx_error (_("PUSHM cannot push R0"));
410 rx_error (_("PUSHM first reg must be <= second reg")); }
412 /* ---------------------------------------------------------------------- */
417 { B2 (0x7e, 0xb0); F ($2, 12, 4); }
419 { B2 (0x6f, 0); F ($2, 8, 4); F ($4, 12, 4); }
421 rx_error (_("POPM cannot pop R0"));
423 rx_error (_("POPM first reg must be <= second reg")); }
425 /* ---------------------------------------------------------------------- */
427 | ADD '#' EXPR ',' REG ',' REG
428 { B2 (0x70, 0x00); F ($5, 8, 4); F ($7, 12, 4); IMM ($3, 6); }
430 /* ---------------------------------------------------------------------- */
433 { B2(0x75, 0x60), UO1 ($3); }
435 /* ---------------------------------------------------------------------- */
437 | BSET '#' EXPR ',' REG
438 { B2 (0x78, 0); FE ($3, 7, 5); F ($5, 12, 4); }
439 | BCLR '#' EXPR ',' REG
440 { B2 (0x7a, 0); FE ($3, 7, 5); F ($5, 12, 4); }
442 /* ---------------------------------------------------------------------- */
444 | BTST '#' EXPR ',' REG
445 { B2 (0x7c, 0x00); FE ($3, 7, 5); F ($5, 12, 4); }
447 /* ---------------------------------------------------------------------- */
450 { B2 (0x7e, 0x30); F ($2, 12, 4); }
452 { B2 (0x7e, 0x40); F ($2, 12, 4); }
454 { B2 (0x7e, 0x50); F ($2, 12, 4); }
456 /* ---------------------------------------------------------------------- */
459 { B2 (0x7e, 0x80); F ($2, 10, 2); F ($3, 12, 4); }
461 /* ---------------------------------------------------------------------- */
464 { B2 (0x7e, 0xb0); F ($2, 12, 4); }
466 /* ---------------------------------------------------------------------- */
470 { B2 (0x7e, 0xc0); F ($2, 12, 4); }
472 as_bad (_("PUSHC can only push the first 16 control registers")); }
474 /* ---------------------------------------------------------------------- */
478 { B2 (0x7e, 0xe0); F ($2, 12, 4); }
480 as_bad (_("POPC can only pop the first 16 control registers")); }
482 /* ---------------------------------------------------------------------- */
485 { B2 (0x7f, 0xa0); F ($2, 12, 4); }
487 { B2 (0x7f, 0xb0); F ($2, 12, 4); }
489 /* ---------------------------------------------------------------------- */
492 { B2 (0x7f, 0x00); F ($2, 12, 4); }
494 { B2 (0x7f, 0x10); F ($2, 12, 4); }
496 { B2 (0x7f, 0x40); F ($3, 12, 4); }
498 { B2 (0x7f, 0x50); F ($3, 12, 4); }
500 /* ---------------------------------------------------------------------- */
503 { B2 (0x7f, 0x83); rx_note_string_insn_use (); }
505 { B2 (0x7f, 0x87); rx_note_string_insn_use (); }
507 { B2 (0x7f, 0x8b); rx_note_string_insn_use (); }
509 { B2 (0x7f, 0x8f); rx_note_string_insn_use (); }
511 /* ---------------------------------------------------------------------- */
514 { B2 (0x7f, 0x80); F ($2, 14, 2); rx_note_string_insn_use (); }
516 { B2 (0x7f, 0x84); F ($2, 14, 2); rx_note_string_insn_use (); }
518 { B2 (0x7f, 0x88); F ($2, 14, 2); }
520 /* ---------------------------------------------------------------------- */
523 { B2 (0x7f, 0x8c); F ($2, 14, 2); rx_note_string_insn_use (); }
525 /* ---------------------------------------------------------------------- */
536 /* ---------------------------------------------------------------------- */
539 { B3 (0x75, 0x70, 0x00); FE ($3, 20, 4); }
541 /* ---------------------------------------------------------------------- */
543 /* rx_disp5op changes the value if it succeeds, so keep it last. */
544 | MOV bwl REG ',' EXPR '[' REG ']'
545 { if ($3 <= 7 && $7 <= 7 && rx_disp5op (&$5, $2))
546 { B2 (0x80, 0); F ($2, 2, 2); F ($7, 9, 3); F ($3, 13, 3); rx_field5s ($5); }
548 { B2 (0xc3, 0x00); F ($2, 2, 2); F ($7, 8, 4); F ($3, 12, 4); DSP ($5, 4, $2); }}
550 /* ---------------------------------------------------------------------- */
552 | MOV bwl EXPR '[' REG ']' ',' REG
553 { if ($5 <= 7 && $8 <= 7 && rx_disp5op (&$3, $2))
554 { B2 (0x88, 0); F ($2, 2, 2); F ($5, 9, 3); F ($8, 13, 3); rx_field5s ($3); }
556 { B2 (0xcc, 0x00); F ($2, 2, 2); F ($5, 8, 4); F ($8, 12, 4); DSP ($3, 6, $2); } }
558 /* ---------------------------------------------------------------------- */
560 /* MOV a,b - if a is a reg and b is mem, src and dest are
563 /* We don't use "disp" here because it causes a shift/reduce
564 conflict with the other displacement-less patterns. */
566 | MOV bwl REG ',' '[' REG ']'
567 { B2 (0xc3, 0x00); F ($2, 2, 2); F ($6, 8, 4); F ($3, 12, 4); }
569 /* ---------------------------------------------------------------------- */
571 | MOV bwl '[' REG ']' ',' disp '[' REG ']'
572 { B2 (0xc0, 0); F ($2, 2, 2); F ($4, 8, 4); F ($9, 12, 4); DSP ($7, 4, $2); }
574 /* ---------------------------------------------------------------------- */
576 | MOV bwl EXPR '[' REG ']' ',' disp '[' REG ']'
577 { B2 (0xc0, 0x00); F ($2, 2, 2); F ($5, 8, 4); F ($10, 12, 4); DSP ($3, 6, $2); DSP ($8, 4, $2); }
579 /* ---------------------------------------------------------------------- */
581 | MOV bwl REG ',' REG
582 { B2 (0xcf, 0x00); F ($2, 2, 2); F ($3, 8, 4); F ($5, 12, 4); }
584 /* ---------------------------------------------------------------------- */
586 | MOV bwl '[' REG ']' ',' REG
587 { B2 (0xcc, 0x00); F ($2, 2, 2); F ($4, 8, 4); F ($7, 12, 4); }
589 /* ---------------------------------------------------------------------- */
591 | BSET '#' EXPR ',' disp '[' REG ']' DOT_B
592 { B2 (0xf0, 0x00); F ($7, 8, 4); FE ($3, 13, 3); DSP ($5, 6, BSIZE); }
593 | BCLR '#' EXPR ',' disp '[' REG ']' DOT_B
594 { B2 (0xf0, 0x08); F ($7, 8, 4); FE ($3, 13, 3); DSP ($5, 6, BSIZE); }
595 | BTST '#' EXPR ',' disp '[' REG ']' DOT_B
596 { B2 (0xf4, 0x00); F ($7, 8, 4); FE ($3, 13, 3); DSP ($5, 6, BSIZE); }
598 /* ---------------------------------------------------------------------- */
600 | PUSH bwl disp '[' REG ']'
601 { B2 (0xf4, 0x08); F ($2, 14, 2); F ($5, 8, 4); DSP ($3, 6, $2); }
603 /* ---------------------------------------------------------------------- */
605 | SBB { sub_op = 0; } op_dp20_rm_l
606 | NEG { sub_op = 1; sub_op2 = 1; } op_dp20_rr
607 | ADC { sub_op = 2; } op_dp20_rim_l
608 | ABS { sub_op = 3; sub_op2 = 2; } op_dp20_rr
609 | MAX { sub_op = 4; } op_dp20_rim
610 | MIN { sub_op = 5; } op_dp20_rim
611 | EMUL { sub_op = 6; } op_dp20_i
612 | EMULU { sub_op = 7; } op_dp20_i
613 | DIV { sub_op = 8; } op_dp20_rim
614 | DIVU { sub_op = 9; } op_dp20_rim
615 | TST { sub_op = 12; } op_dp20_rim
616 | XOR { sub_op = 13; } op_dp20_rim
617 | NOT { sub_op = 14; sub_op2 = 0; } op_dp20_rr
618 | STZ { sub_op = 14; } op_dp20_i
619 | STNZ { sub_op = 15; } op_dp20_i
621 /* ---------------------------------------------------------------------- */
623 | EMUL { sub_op = 6; } op_xchg
624 | EMULU { sub_op = 7; } op_xchg
625 | XCHG { sub_op = 16; } op_xchg
626 | ITOF { sub_op = 17; } op_xchg
628 /* ---------------------------------------------------------------------- */
631 { id24 (1, 0x63, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
633 { id24 (1, 0x67, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
635 { id24 (1, 0x6b, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
637 { id24 (1, 0x6f, 0x00); F ($4, 16, 4); F ($2, 20, 4); }
639 | BSET REG ',' disp '[' REG ']' opt_b
640 { id24 (1, 0x60, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
641 | BCLR REG ',' disp '[' REG ']' opt_b
642 { id24 (1, 0x64, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
643 | BTST REG ',' disp '[' REG ']' opt_b
644 { id24 (1, 0x68, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
645 | BNOT REG ',' disp '[' REG ']' opt_b
646 { id24 (1, 0x6c, 0x00); F ($6, 16, 4); F ($2, 20, 4); DSP ($4, 14, BSIZE); }
648 /* ---------------------------------------------------------------------- */
650 | FSUB { sub_op = 0; } float2_op
651 | FCMP { sub_op = 1; } float2_op
652 | FADD { sub_op = 2; } float2_op
653 | FMUL { sub_op = 3; } float2_op
654 | FDIV { sub_op = 4; } float2_op
655 | FTOI { sub_op = 5; } float2_op_ni
656 | ROUND { sub_op = 6; } float2_op_ni
658 /* ---------------------------------------------------------------------- */
661 { id24 (1, 0xdb, 0x00); F ($1, 20, 4); F ($3, 16, 4); }
662 | SCCND bwl disp '[' REG ']'
663 { id24 (1, 0xd0, 0x00); F ($1, 20, 4); F ($2, 12, 2); F ($5, 16, 4); DSP ($3, 14, $2); }
665 /* ---------------------------------------------------------------------- */
667 | BMCND '#' EXPR ',' disp '[' REG ']' opt_b
668 { id24 (1, 0xe0, 0x00); F ($1, 20, 4); FE ($3, 11, 3);
669 F ($7, 16, 4); DSP ($5, 14, BSIZE); }
671 /* ---------------------------------------------------------------------- */
673 | BNOT '#' EXPR ',' disp '[' REG ']' opt_b
674 { id24 (1, 0xe0, 0x0f); FE ($3, 11, 3); F ($7, 16, 4);
675 DSP ($5, 14, BSIZE); }
677 /* ---------------------------------------------------------------------- */
680 { id24 (2, 0x00, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
682 { id24 (2, 0x01, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
684 { id24 (2, 0x04, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
686 { id24 (2, 0x05, 0x00); F ($2, 16, 4); F ($4, 20, 4); }
688 /* ---------------------------------------------------------------------- */
690 /* We don't have syntax for these yet. */
692 { id24 (2, 0x17, 0x00); F ($2, 20, 4); }
694 { id24 (2, 0x17, 0x10); F ($2, 20, 4); }
696 { id24 (2, 0x1f, 0x00); F ($2, 20, 4); }
698 { id24 (2, 0x1f, 0x20); F ($2, 20, 4); }
700 { id24 (2, 0x1f, 0x10); F ($2, 20, 4); }
703 { id24 (2, 0x18, 0x00);
704 if (rx_uintop ($3, 4) && $3.X_add_number == 1)
706 else if (rx_uintop ($3, 4) && $3.X_add_number == 2)
709 as_bad (_("RACW expects #1 or #2"));}
711 /* ---------------------------------------------------------------------- */
713 | MOV bwl REG ',' '[' REG '+' ']'
714 { id24 (2, 0x20, 0); F ($2, 14, 2); F ($6, 16, 4); F ($3, 20, 4); }
715 | MOV bwl REG ',' '[' '-' REG ']'
716 { id24 (2, 0x24, 0); F ($2, 14, 2); F ($7, 16, 4); F ($3, 20, 4); }
718 /* ---------------------------------------------------------------------- */
720 | MOV bwl '[' REG '+' ']' ',' REG
721 { id24 (2, 0x28, 0); F ($2, 14, 2); F ($4, 16, 4); F ($8, 20, 4); }
722 | MOV bwl '[' '-' REG ']' ',' REG
723 { id24 (2, 0x2c, 0); F ($2, 14, 2); F ($5, 16, 4); F ($8, 20, 4); }
725 /* ---------------------------------------------------------------------- */
727 | MOVU bw '[' REG '+' ']' ',' REG
728 { id24 (2, 0x38, 0); F ($2, 15, 1); F ($4, 16, 4); F ($8, 20, 4); }
729 | MOVU bw '[' '-' REG ']' ',' REG
730 { id24 (2, 0x3c, 0); F ($2, 15, 1); F ($5, 16, 4); F ($8, 20, 4); }
732 /* ---------------------------------------------------------------------- */
734 | ROTL { sub_op = 6; } op_shift_rot
735 | ROTR { sub_op = 4; } op_shift_rot
736 | REVW { sub_op = 5; } op_shift_rot
737 | REVL { sub_op = 7; } op_shift_rot
739 /* ---------------------------------------------------------------------- */
742 { id24 (2, 0x68, 0x00); F ($4 % 16, 20, 4); F ($4 / 16, 15, 1);
745 /* ---------------------------------------------------------------------- */
748 { id24 (2, 0x6a, 0); F ($2, 15, 5); F ($4, 20, 4); }
750 /* ---------------------------------------------------------------------- */
752 | ROTL '#' EXPR ',' REG
753 { id24 (2, 0x6e, 0); FE ($3, 15, 5); F ($5, 20, 4); }
754 | ROTR '#' EXPR ',' REG
755 { id24 (2, 0x6c, 0); FE ($3, 15, 5); F ($5, 20, 4); }
757 /* ---------------------------------------------------------------------- */
759 | MVTC '#' EXPR ',' CREG
760 { id24 (2, 0x73, 0x00); F ($5, 19, 5); IMM ($3, 12); }
762 /* ---------------------------------------------------------------------- */
764 | BMCND '#' EXPR ',' REG
765 { id24 (2, 0xe0, 0x00); F ($1, 16, 4); FE ($3, 11, 5);
768 /* ---------------------------------------------------------------------- */
770 | BNOT '#' EXPR ',' REG
771 { id24 (2, 0xe0, 0xf0); FE ($3, 11, 5); F ($5, 20, 4); }
773 /* ---------------------------------------------------------------------- */
775 | MOV bwl REG ',' '[' REG ',' REG ']'
776 { id24 (3, 0x00, 0); F ($2, 10, 2); F ($6, 12, 4); F ($8, 16, 4); F ($3, 20, 4); }
778 | MOV bwl '[' REG ',' REG ']' ',' REG
779 { id24 (3, 0x40, 0); F ($2, 10, 2); F ($4, 12, 4); F ($6, 16, 4); F ($9, 20, 4); }
781 | MOVU bw '[' REG ',' REG ']' ',' REG
782 { id24 (3, 0xc0, 0); F ($2, 10, 2); F ($4, 12, 4); F ($6, 16, 4); F ($9, 20, 4); }
784 /* ---------------------------------------------------------------------- */
786 | SUB { sub_op = 0; } op_subadd
787 | ADD { sub_op = 2; } op_subadd
788 | MUL { sub_op = 3; } op_subadd
789 | AND_ { sub_op = 4; } op_subadd
790 | OR { sub_op = 5; } op_subadd
792 /* ---------------------------------------------------------------------- */
793 /* There is no SBB #imm so we fake it with ADC. */
795 | SBB '#' EXPR ',' REG
796 { id24 (2, 0x70, 0x20); F ($5, 20, 4); NBIMM ($3, 12); }
798 /* ---------------------------------------------------------------------- */
802 /* ====================================================================== */
806 { B2 (0x43 + (sub_op<<2), 0); F ($1, 8, 4); F ($3, 12, 4); }
807 | disp '[' REG ']' DOT_UB ',' REG
808 { B2 (0x40 + (sub_op<<2), 0); F ($3, 8, 4); F ($7, 12, 4); DSP ($1, 6, BSIZE); }
809 | disp '[' REG ']' memex ',' REG
810 { B3 (MEMEX, sub_op<<2, 0); F ($5, 8, 2); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, sizemap[$5]); }
811 | REG ',' REG ',' REG
812 { id24 (4, sub_op<<4, 0), F ($5, 12, 4), F ($1, 16, 4), F ($3, 20, 4); }
815 /* sbb, neg, adc, abs, max, min, div, divu, tst, not, xor, stz, stnz, emul, emulu */
819 { id24 (1, 0x03 + (sub_op<<2), 0x00); F ($1, 16, 4); F ($3, 20, 4); }
820 | disp '[' REG ']' opt_l ',' REG
821 { B4 (MEMEX, 0xa0, 0x00 + sub_op, 0x00);
822 F ($3, 24, 4); F ($7, 28, 4); DSP ($1, 14, LSIZE); }
825 /* neg, adc, abs, max, min, div, divu, tst, not, xor, stz, stnz, emul, emulu */
829 { id24 (1, 0x03 + (sub_op<<2), 0x00); F ($1, 16, 4); F ($3, 20, 4); }
830 | disp '[' REG ']' DOT_UB ',' REG
831 { id24 (1, 0x00 + (sub_op<<2), 0x00); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, BSIZE); }
832 | disp '[' REG ']' memex ',' REG
833 { B4 (MEMEX, 0x20 + ($5 << 6), 0x00 + sub_op, 0x00);
834 F ($3, 24, 4); F ($7, 28, 4); DSP ($1, 14, sizemap[$5]); }
839 { id24 (2, 0x70, sub_op<<4); F ($4, 20, 4); IMM ($2, 12); }
854 { id24 (1, 0x03 + (sub_op<<2), 0x00); F ($1, 16, 4); F ($3, 20, 4); }
856 { B2 (0x7e, sub_op2 << 4); F ($1, 12, 4); }
859 /* xchg, itof, emul, emulu */
862 { id24 (1, 0x03 + (sub_op<<2), 0); F ($1, 16, 4); F ($3, 20, 4); }
863 | disp '[' REG ']' DOT_UB ',' REG
864 { id24 (1, 0x00 + (sub_op<<2), 0); F ($3, 16, 4); F ($7, 20, 4); DSP ($1, 14, BSIZE); }
865 | disp '[' REG ']' memex ',' REG
866 { B4 (MEMEX, 0x20, 0x00 + sub_op, 0); F ($5, 8, 2); F ($3, 24, 4); F ($7, 28, 4);
867 DSP ($1, 14, sizemap[$5]); }
870 /* 000:SHLR, 001:SHAR, 010:SHLL, 011:-, 100:ROTR, 101:REVW, 110:ROTL, 111:REVL */
873 { id24 (2, 0x60 + sub_op, 0); F ($1, 16, 4); F ($3, 20, 4); }
877 { B2 (0x68 + (sub_op<<1), 0); FE ($2, 7, 5); F ($4, 12, 4); }
878 | '#' EXPR ',' REG ',' REG
879 { id24 (2, 0x80 + (sub_op << 5), 0); FE ($2, 11, 5); F ($4, 16, 4); F ($6, 20, 4); }
885 : { rx_check_float_support (); }
887 { id24 (2, 0x72, sub_op << 4); F ($5, 20, 4); O4 ($3); }
892 : { rx_check_float_support (); }
894 { id24 (1, 0x83 + (sub_op << 2), 0); F ($2, 16, 4); F ($4, 20, 4); }
895 | { rx_check_float_support (); }
896 disp '[' REG ']' opt_l ',' REG
897 { id24 (1, 0x80 + (sub_op << 2), 0); F ($4, 16, 4); F ($8, 20, 4); DSP ($2, 14, LSIZE); }
900 /* ====================================================================== */
902 disp : { $$ = zero_expr (); }
906 flag : { need_flag = 1; } FLAG { need_flag = 0; $$ = $2; }
909 /* DOT_UB is not listed here, it's handled with a separate pattern. */
910 /* Use sizemap[$n] to get LSIZE etc. */
911 memex : DOT_B { $$ = 0; }
918 bwl : { $$ = LSIZE; }
919 | DOT_B { $$ = BSIZE; }
920 | DOT_W { $$ = WSIZE; }
921 | DOT_L { $$ = LSIZE; }
938 /* ====================================================================== */
977 { "fintv", CREG, 11 },
978 { "intb", CREG, 12 },
981 { "pben", CREG, 17 },
983 { "bbpsw", CREG, 24 },
984 { "bbpc", CREG, 25 },
991 { ".ub", DOT_UB, 0 },
992 { ".uw", DOT_UW , 0},
1001 #define OPC(x) { #x, x, IS_OPCODE }
1005 { "and", AND_, IS_OPCODE },
1103 #define NUM_TOKENS (sizeof (token_table) / sizeof (token_table[0]))
1110 condition_opcode_table[] =
1117 #define NUM_CONDITION_OPCODES (sizeof (condition_opcode_table) / sizeof (condition_opcode_table[0]))
1148 #define NUM_CONDITIONS (sizeof (condition_table) / sizeof (condition_table[0]))
1151 rx_lex_init (char * beginning, char * ending)
1153 rx_init_start = beginning;
1154 rx_lex_start = beginning;
1155 rx_lex_end = ending;
1163 check_condition (char * base)
1168 if ((unsigned) (rx_lex_end - rx_lex_start) < strlen (base) + 1)
1170 if (memcmp (rx_lex_start, base, strlen (base)))
1172 cp = rx_lex_start + strlen (base);
1173 for (i = 0; i < NUM_CONDITIONS; i ++)
1175 if (strcasecmp (cp, condition_table[i].string) == 0)
1177 rx_lval.regno = condition_table[i].val;
1188 char * save_input_pointer;
1190 while (ISSPACE (*rx_lex_start)
1191 && rx_lex_start != rx_lex_end)
1194 rx_last_exp_start = rx_lex_start;
1196 if (rx_lex_start == rx_lex_end)
1199 if (ISALPHA (*rx_lex_start)
1200 || (rx_pid_register != -1 && memcmp (rx_lex_start, "%pidreg", 7) == 0)
1201 || (rx_gp_register != -1 && memcmp (rx_lex_start, "%gpreg", 6) == 0)
1202 || (*rx_lex_start == '.' && ISALPHA (rx_lex_start[1])))
1208 for (e = rx_lex_start + 1;
1209 e < rx_lex_end && ISALNUM (*e);
1215 if (strcmp (rx_lex_start, "%pidreg") == 0)
1218 rx_lval.regno = rx_pid_register;
1221 rx_last_token = REG;
1226 if (strcmp (rx_lex_start, "%gpreg") == 0)
1229 rx_lval.regno = rx_gp_register;
1232 rx_last_token = REG;
1237 if (rx_last_token == 0)
1238 for (ci = 0; ci < NUM_CONDITION_OPCODES; ci ++)
1239 if (check_condition (condition_opcode_table[ci].string))
1243 rx_last_token = condition_opcode_table[ci].token;
1244 return condition_opcode_table[ci].token;
1247 for (i = 0; i < NUM_TOKENS; i++)
1248 if (strcasecmp (rx_lex_start, token_table[i].string) == 0
1249 && !(token_table[i].val == IS_OPCODE && rx_last_token != 0)
1250 && !(token_table[i].token == FLAG && !need_flag))
1252 rx_lval.regno = token_table[i].val;
1255 rx_last_token = token_table[i].token;
1256 return token_table[i].token;
1261 if (rx_last_token == 0)
1263 rx_last_token = UNKNOWN_OPCODE;
1264 return UNKNOWN_OPCODE;
1267 if (rx_last_token == UNKNOWN_OPCODE)
1270 if (*rx_lex_start == '[')
1272 if (*rx_lex_start == ']')
1276 || rx_last_token == REG
1277 || strchr ("[],#", *rx_lex_start))
1279 rx_last_token = *rx_lex_start;
1280 return *rx_lex_start ++;
1283 save_input_pointer = input_line_pointer;
1284 input_line_pointer = rx_lex_start;
1285 rx_lval.exp.X_md = 0;
1286 expression (&rx_lval.exp);
1288 /* We parse but ignore any :<size> modifier on expressions. */
1289 if (*input_line_pointer == ':')
1293 for (cp = input_line_pointer + 1; *cp && cp < rx_lex_end; cp++)
1296 if (cp > input_line_pointer+1)
1297 input_line_pointer = cp;
1300 rx_lex_start = input_line_pointer;
1301 input_line_pointer = save_input_pointer;
1302 rx_last_token = EXPR;
1307 rx_error (const char * str)
1311 len = rx_last_exp_start - rx_init_start;
1313 as_bad ("%s", rx_init_start);
1314 as_bad ("%*s^ %s", len, "", str);
1319 rx_intop (expressionS exp, int nbits, int opbits)
1324 if (exp.X_op == O_big && nbits == 32)
1326 if (exp.X_op != O_constant)
1328 v = exp.X_add_number;
1330 msb = 1UL << (opbits - 1);
1331 mask = (1UL << opbits) - 1;
1333 if ((v & msb) && ! (v & ~mask))
1339 return -0x8 <= v && v <= 0x7;
1341 return -0x10 <= v && v <= 0x17;
1343 return -0x80 <= v && v <= 0x7f;
1345 return -0x8000 <= v && v <= 0x7fff;
1347 return -0x800000 <= v && v <= 0x7fffff;
1351 printf ("rx_intop passed %d\n", nbits);
1358 rx_uintop (expressionS exp, int nbits)
1362 if (exp.X_op != O_constant)
1364 v = exp.X_add_number;
1375 return v <= 0xffffff;
1377 printf ("rx_uintop passed %d\n", nbits);
1384 rx_disp3op (expressionS exp)
1388 if (exp.X_op != O_constant)
1390 v = exp.X_add_number;
1391 if (v < 3 || v > 10)
1397 rx_disp5op (expressionS * exp, int msize)
1401 if (exp->X_op != O_constant)
1403 v = exp->X_add_number;
1408 if (0 <= v && v <= 31)
1414 if (0 <= v && v <= 63)
1416 exp->X_add_number >>= 1;
1423 if (0 <= v && v <= 127)
1425 exp->X_add_number >>= 2;
1433 /* Just like the above, but allows a zero displacement. */
1436 rx_disp5op0 (expressionS * exp, int msize)
1438 if (exp->X_op != O_constant)
1440 if (exp->X_add_number == 0)
1442 return rx_disp5op (exp, msize);
1446 exp_val (expressionS exp)
1448 if (exp.X_op != O_constant)
1450 rx_error (_("constant expected"));
1453 return exp.X_add_number;
1459 /* Static, so program load sets it to all zeros, which is what we want. */
1460 static expressionS zero;
1461 zero.X_op = O_constant;
1466 immediate (expressionS exp, int type, int pos, int bits)
1468 /* We will emit constants ourself here, so negate them. */
1469 if (type == RXREL_NEGATIVE && exp.X_op == O_constant)
1470 exp.X_add_number = - exp.X_add_number;
1471 if (type == RXREL_NEGATIVE_BORROW)
1473 if (exp.X_op == O_constant)
1474 exp.X_add_number = - exp.X_add_number - 1;
1476 rx_error (_("sbb cannot use symbolic immediates"));
1479 if (rx_intop (exp, 8, bits))
1481 rx_op (exp, 1, type);
1484 else if (rx_intop (exp, 16, bits))
1486 rx_op (exp, 2, type);
1489 else if (rx_uintop (exp, 16) && bits == 16)
1491 rx_op (exp, 2, type);
1494 else if (rx_intop (exp, 24, bits))
1496 rx_op (exp, 3, type);
1499 else if (rx_intop (exp, 32, bits))
1501 rx_op (exp, 4, type);
1504 else if (type == RXREL_SIGNED)
1506 /* This is a symbolic immediate, we will relax it later. */
1507 rx_relax (RX_RELAX_IMM, pos);
1508 rx_op (exp, linkrelax ? 4 : 1, type);
1513 /* Let the linker deal with it. */
1514 rx_op (exp, 4, type);
1520 displacement (expressionS exp, int msize)
1525 if (exp.X_op == O_symbol
1530 case BFD_RELOC_GPREL16:
1534 exp.X_md = BFD_RELOC_RX_GPRELB;
1537 exp.X_md = BFD_RELOC_RX_GPRELW;
1540 exp.X_md = BFD_RELOC_RX_GPRELL;
1548 if (exp.X_op == O_subtract)
1550 exp.X_md = BFD_RELOC_RX_DIFF;
1555 if (exp.X_op != O_constant)
1557 rx_error (_("displacements must be constants"));
1560 val = exp.X_add_number;
1571 rx_error (_("word displacement not word-aligned"));
1576 rx_error (_("long displacement not long-aligned"));
1580 as_bad (_("displacement with unknown size (internal bug?)\n"));
1585 exp.X_add_number = val;
1587 if (0 <= val && val <= 255 )
1593 if (0 <= val && val <= 65535)
1599 rx_error (_("negative displacements not allowed"));
1601 rx_error (_("displacement too large"));
1606 rtsd_immediate (expressionS exp)
1610 if (exp.X_op != O_constant)
1612 rx_error (_("rtsd size must be constant"));
1615 val = exp.X_add_number;
1617 rx_error (_("rtsd size must be multiple of 4"));
1619 if (val < 0 || val > 1020)
1620 rx_error (_("rtsd size must be 0..1020"));
1623 exp.X_add_number = val;
1628 rx_range (expressionS exp, int minv, int maxv)
1632 if (exp.X_op != O_constant)
1635 val = exp.X_add_number;
1636 if (val < minv || val > maxv)
1637 as_warn (_("Value %d out of range %d..%d"), val, minv, maxv);
1641 rx_check_float_support (void)
1643 if (rx_cpu == RX100 || rx_cpu == RX200)
1644 rx_error (_("target CPU type does not support floating point instructions"));