diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 22 | ||||
-rw-r--r-- | gas/Makefile.am | 11 | ||||
-rw-r--r-- | gas/Makefile.in | 26 | ||||
-rw-r--r-- | gas/NEWS | 2 | ||||
-rw-r--r-- | gas/config/rl78-defs.h | 51 | ||||
-rw-r--r-- | gas/config/rl78-parse.y | 1532 | ||||
-rw-r--r-- | gas/config/tc-rl78.c | 701 | ||||
-rw-r--r-- | gas/config/tc-rl78.h | 75 | ||||
-rwxr-xr-x | gas/configure | 7 | ||||
-rw-r--r-- | gas/configure.in | 7 | ||||
-rw-r--r-- | gas/configure.tgt | 1 | ||||
-rw-r--r-- | gas/doc/Makefile.am | 1 | ||||
-rw-r--r-- | gas/doc/Makefile.in | 1 | ||||
-rw-r--r-- | gas/doc/all.texi | 1 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 7 | ||||
-rw-r--r-- | gas/doc/c-rl78.texi | 121 |
16 files changed, 2566 insertions, 0 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index b06ac94..9036a16 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,25 @@ +2011-11-01 DJ Delorie <dj@redhat.com> + + * Makefile.am (TARGET_CPU_CFILES): Add tc-rl78.c. + (TARGET_CPU_HFILES): Add rc-rl78.h. + (EXTRA_DIST): Add rl78-parse.c and rl78-parse.y. + (rl78-parse.c, rl78-parse.h, rl78-parse.o, rl78-defs.h): New rules. + * Makefile.in: Regenerate. + * configure.in: Add rl78 case. + * configure: Regenerate. + * configure.tgt: Add rl78 case. + * config/rl78-defs.h: New file. + * config/rl78-parse.y: New file. + * config/tc-rl78.c: New file. + * config/tc-rl78.h: New file. + * NEWS: Add Renesas RL78. + + * doc/Makefile.am (c-rl78.texi): New. + * doc/Makefile.in: Likewise. + * doc/all.texi: Enable it. + * doc/as.texi: Add it. + * doc/c-rl78.texi: New file. + 2011-10-28 Walter Lee <walt@tilera.com> * NEWS: Fix TILEPro capitalization. diff --git a/gas/Makefile.am b/gas/Makefile.am index 4bd21b3..8f7b7cd 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -151,6 +151,7 @@ TARGET_CPU_CFILES = \ config/tc-pdp11.c \ config/tc-pj.c \ config/tc-ppc.c \ + config/tc-rl78.c \ config/tc-rx.c \ config/tc-s390.c \ config/tc-score.c \ @@ -217,6 +218,7 @@ TARGET_CPU_HFILES = \ config/tc-pdp11.h \ config/tc-pj.h \ config/tc-ppc.h \ + config/tc-rl78.h \ config/tc-rx.h \ config/tc-s390.h \ config/tc-score.h \ @@ -336,6 +338,7 @@ EXTRA_SCRIPTS = .gdbinit EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c \ bfin-parse.c bfin-parse.h bfin-lex.c \ + rl78-parse.c rl78-parse.h \ rx-parse.c rx-parse.h diststuff: $(EXTRA_DIST) info @@ -465,6 +468,14 @@ endif $(COMPILE) -c `test -f bfin-lex.c || echo $(srcdir)/`bfin-lex.c $(NO_WERROR) endif +rl78-parse.c: $(srcdir)/config/rl78-parse.y + $(SHELL) $(YLWRAP) $(srcdir)/config/rl78-parse.y y.tab.c rl78-parse.c y.tab.h rl78-parse.h -- $(YACCCOMPILE) -d ; +rl78-parse.h: rl78-parse.c +rl78-parse.@OBJEXT@: rl78-parse.c rl78-parse.h $(srcdir)/config/rl78-defs.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/rl78.h $(BFDDIR)/libbfd.h + +rl78-defs.h: ; @true + rx-parse.c: $(srcdir)/config/rx-parse.y $(SHELL) $(YLWRAP) $(srcdir)/config/rx-parse.y y.tab.c rx-parse.c y.tab.h rx-parse.h -- $(YACCCOMPILE) -d ; rx-parse.h: rx-parse.c diff --git a/gas/Makefile.in b/gas/Makefile.in index ccc7db7..39af3e8 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -418,6 +418,7 @@ TARGET_CPU_CFILES = \ config/tc-pdp11.c \ config/tc-pj.c \ config/tc-ppc.c \ + config/tc-rl78.c \ config/tc-rx.c \ config/tc-s390.c \ config/tc-score.c \ @@ -484,6 +485,7 @@ TARGET_CPU_HFILES = \ config/tc-pdp11.h \ config/tc-pj.h \ config/tc-ppc.h \ + config/tc-rl78.h \ config/tc-rx.h \ config/tc-s390.h \ config/tc-score.h \ @@ -596,6 +598,7 @@ noinst_SCRIPTS = $(GDBINIT) EXTRA_SCRIPTS = .gdbinit EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c \ bfin-parse.c bfin-parse.h bfin-lex.c \ + rl78-parse.c rl78-parse.h \ rx-parse.c rx-parse.h DISTCLEANFILES = targ-cpu.h obj-format.h targ-env.h itbl-cpu.h cgen-desc.h @@ -831,6 +834,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-pdp11.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-pj.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-ppc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-rl78.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-rx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-s390.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-score.Po@am__quote@ @@ -1492,6 +1496,20 @@ tc-ppc.obj: config/tc-ppc.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-ppc.obj `if test -f 'config/tc-ppc.c'; then $(CYGPATH_W) 'config/tc-ppc.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-ppc.c'; fi` +tc-rl78.o: config/tc-rl78.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-rl78.o -MD -MP -MF $(DEPDIR)/tc-rl78.Tpo -c -o tc-rl78.o `test -f 'config/tc-rl78.c' || echo '$(srcdir)/'`config/tc-rl78.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-rl78.Tpo $(DEPDIR)/tc-rl78.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-rl78.c' object='tc-rl78.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-rl78.o `test -f 'config/tc-rl78.c' || echo '$(srcdir)/'`config/tc-rl78.c + +tc-rl78.obj: config/tc-rl78.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-rl78.obj -MD -MP -MF $(DEPDIR)/tc-rl78.Tpo -c -o tc-rl78.obj `if test -f 'config/tc-rl78.c'; then $(CYGPATH_W) 'config/tc-rl78.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-rl78.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-rl78.Tpo $(DEPDIR)/tc-rl78.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-rl78.c' object='tc-rl78.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-rl78.obj `if test -f 'config/tc-rl78.c'; then $(CYGPATH_W) 'config/tc-rl78.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-rl78.c'; fi` + tc-rx.o: config/tc-rx.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-rx.o -MD -MP -MF $(DEPDIR)/tc-rx.Tpo -c -o tc-rx.o `test -f 'config/tc-rx.c' || echo '$(srcdir)/'`config/tc-rx.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-rx.Tpo $(DEPDIR)/tc-rx.Po @@ -2436,6 +2454,14 @@ bfin-lex.@OBJEXT@: bfin-lex.c bfin-parse.h $(srcdir)/config/bfin-defs.h @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `test -f bfin-lex.c || echo $(srcdir)/`bfin-lex.c $(NO_WERROR) +rl78-parse.c: $(srcdir)/config/rl78-parse.y + $(SHELL) $(YLWRAP) $(srcdir)/config/rl78-parse.y y.tab.c rl78-parse.c y.tab.h rl78-parse.h -- $(YACCCOMPILE) -d ; +rl78-parse.h: rl78-parse.c +rl78-parse.@OBJEXT@: rl78-parse.c rl78-parse.h $(srcdir)/config/rl78-defs.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/rl78.h $(BFDDIR)/libbfd.h + +rl78-defs.h: ; @true + rx-parse.c: $(srcdir)/config/rx-parse.y $(SHELL) $(YLWRAP) $(srcdir)/config/rx-parse.y y.tab.c rx-parse.c y.tab.h rx-parse.h -- $(YACCCOMPILE) -d ; rx-parse.h: rx-parse.c @@ -1,5 +1,7 @@ -*- text -*- +* Add support for the Renesas RL78 architecture. + * Add support for the Adapteva EPIPHANY architecture. Changes in 2.22: diff --git a/gas/config/rl78-defs.h b/gas/config/rl78-defs.h new file mode 100644 index 0000000..e33e4f9 --- /dev/null +++ b/gas/config/rl78-defs.h @@ -0,0 +1,51 @@ +/* rl78-defs.h Renesas RL78 internal definitions + 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. */ + +#ifndef RL78_DEFS_H +#define RL78_DEFS_H + +/* Third operand to rl78_op. */ +#define RL78REL_DATA 0 +#define RL78REL_PCREL 1 + +extern int rl78_error (char *); +extern void rl78_lex_init (char *, char *); +extern void rl78_prefix (int); +extern int rl78_has_prefix (void); +extern void rl78_base1 (int); +extern void rl78_base2 (int, int); +extern void rl78_base3 (int, int, int); +extern void rl78_base4 (int, int, int, int); +extern void rl78_field (int, int, int); +extern void rl78_op (expressionS, int, int); +extern void rl78_disp3 (expressionS, int); +extern void rl78_field5s (expressionS); +extern void rl78_field5s2 (expressionS); +extern void rl78_relax (int, int); +extern void rl78_linkrelax_dsp (int); +extern void rl78_linkrelax_imm (int); +extern void rl78_linkrelax_branch (void); +extern int rl78_parse (void); +extern int rl78_wrap (void); + +extern char * rl78_lex_start; +extern char * rl78_lex_end; +#endif diff --git a/gas/config/rl78-parse.y b/gas/config/rl78-parse.y new file mode 100644 index 0000000..431ae6f --- /dev/null +++ b/gas/config/rl78-parse.y @@ -0,0 +1,1532 @@ +/* rl78-parse.y Renesas RL78 parser + Copyright 2011 + 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 "rl78-defs.h" + +static int rl78_lex (void); + +/* 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) rl78_base1 (b1) +#define B2(b1, b2) rl78_base2 (b1, b2) +#define B3(b1, b2, b3) rl78_base3 (b1, b2, b3) +#define B4(b1, b2, b3, b4) rl78_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) rl78_field (val, pos, sz) +#define FE(exp,pos,sz) rl78_field (exp_val (exp), pos, sz); + +#define O1(v) rl78_op (v, 1, RL78REL_DATA) +#define O2(v) rl78_op (v, 2, RL78REL_DATA) +#define O3(v) rl78_op (v, 3, RL78REL_DATA) +#define O4(v) rl78_op (v, 4, RL78REL_DATA) + +#define PC1(v) rl78_op (v, 1, RL78REL_PCREL) +#define PC2(v) rl78_op (v, 2, RL78REL_PCREL) +#define PC3(v) rl78_op (v, 3, RL78REL_PCREL) + +#define IMM(v,pos) F (immediate (v, RL78REL_SIGNED, pos), pos, 2); \ + if (v.X_op != O_constant && v.X_op != O_big) rl78_linkrelax_imm (pos) +#define NIMM(v,pos) F (immediate (v, RL78REL_NEGATIVE, pos), pos, 2) +#define NBIMM(v,pos) F (immediate (v, RL78REL_NEGATIVE_BORROW, pos), pos, 2) +#define DSP(v,pos,msz) if (!v.X_md) rl78_relax (RL78_RELAX_DISP, pos); \ + else rl78_linkrelax_dsp (pos); \ + F (displacement (v, msz), pos, 2) + +#define id24(a,b2,b3) B3 (0xfb+a, b2, b3) + +static int expr_is_sfr (expressionS); +static int expr_is_saddr (expressionS); +static int expr_is_word_aligned (expressionS); +static int exp_val (expressionS exp); + +static int need_flag = 0; +static int rl78_in_brackets = 0; +static int rl78_last_token = 0; +static char * rl78_init_start; +static char * rl78_last_exp_start = 0; + +#define YYDEBUG 1 +#define YYERROR_VERBOSE 1 + +#define NOT_SADDR rl78_error ("Expression not 0xFFE20 to 0xFFF1F") +#define SA(e) if (!expr_is_saddr (e)) NOT_SADDR; + +#define NOT_SFR rl78_error ("Expression not 0xFFF00 to 0xFFFFF") +#define SFR(e) if (!expr_is_sfr (e)) NOT_SFR; + +#define NOT_SFR_OR_SADDR rl78_error ("Expression not 0xFFE20 to 0xFFFFF") + +#define NOT_ES if (rl78_has_prefix()) rl78_error ("ES: prefix not allowed here"); + +#define WA(x) if (!expr_is_word_aligned (x)) rl78_error ("Expression not word-aligned"); + +static void check_expr_is_bit_index (expressionS); +#define Bit(e) check_expr_is_bit_index (e); + +/* Returns TRUE (non-zero) if the expression is a constant in the + given range. */ +static int check_expr_is_const (expressionS, int vmin, int vmax); + +/* Convert a "regb" value to a "reg_xbc" value. Error if other + registers are passed. Needed to avoid reduce-reduce conflicts. */ +static int +reg_xbc (int reg) +{ + switch (reg) + { + case 0: /* X */ + return 0x10; + case 3: /* B */ + return 0x20; + case 2: /* C */ + return 0x30; + default: + rl78_error ("Only X, B, or C allowed here"); + return 0; + } +} + +%} + +%name-prefix="rl78_" + +%union { + int regno; + expressionS exp; +} + +%type <regno> regb regb_na regw regw_na FLAG sfr +%type <regno> A X B C D E H L AX BC DE HL +%type <exp> EXPR + +%type <regno> addsub addsubw andor1 bt_bf setclr1 oneclrb oneclrw +%type <regno> incdec incdecw + +%token A X B C D E H L AX BC DE HL +%token SPL SPH PSW CS ES PMC MEM +%token FLAG SP CY +%token RB0 RB1 RB2 RB3 + +%token EXPR UNKNOWN_OPCODE IS_OPCODE + +%token DOT_S DOT_B DOT_W DOT_L DOT_A DOT_UB DOT_UW + +%token ADD ADDC ADDW AND_ AND1 +/* BC is also a register pair */ +%token BF BH BNC BNH BNZ BR BRK BRK1 BT BTCLR BZ +%token CALL CALLT CLR1 CLRB CLRW CMP CMP0 CMPS CMPW +%token DEC DECW DI DIVHU DIVWU +%token EI +%token HALT +%token INC INCW +%token MACH MACHU MOV MOV1 MOVS MOVW MULH MULHU MULU +%token NOP +%token ONEB ONEW OR OR1 +%token POP PUSH +%token RET RETI RETB ROL ROLC ROLWC ROR RORC +%token SAR SARW SEL SET1 SHL SHLW SHR SHRW +%token SKC SKH SKNC SKNH SKNZ SKZ STOP SUB SUBC SUBW +%token XCH XCHW XOR XOR1 + +%% +/* ====================================================================== */ + +statement : + + UNKNOWN_OPCODE + { as_bad (_("Unknown opcode: %s"), rl78_init_start); } + +/* The opcodes are listed in approximately alphabetical order. */ + +/* For reference: + + sfr = special function register - symbol, 0xFFF00 to 0xFFFFF + sfrp = special function register - symbol, 0xFFF00 to 0xFFFFE, even only + saddr = 0xFFE20 to 0xFFF1F + saddrp = 0xFFE20 to 0xFFF1E, even only + + addr20 = 0x00000 to 0xFFFFF + addr16 = 0x00000 to 0x0FFFF, even only for 16-bit ops + addr5 = 0x00000 to 0x000BE, even only +*/ + +/* ---------------------------------------------------------------------- */ + +/* addsub is ADD, ADDC, SUB, SUBC, AND, OR, XOR, and parts of CMP. */ + + | addsub A ',' '#' EXPR + { B1 (0x0c|$1); O1 ($5); } + + | addsub EXPR {SA($2)} ',' '#' EXPR + { B1 (0x0a|$1); O1 ($2); O1 ($6); } + + | addsub A ',' A + { B2 (0x61, 0x01|$1); } + + | addsub A ',' regb_na + { B2 (0x61, 0x08|$1); F ($4, 13, 3); } + + | addsub regb_na ',' A + { B2 (0x61, 0x00|$1); F ($2, 13, 3); } + + | addsub A ',' EXPR {SA($4)} + { B1 (0x0b|$1); O1 ($4); } + + | addsub A ',' opt_es '!' EXPR + { B1 (0x0f|$1); O2 ($6); } + + | addsub A ',' opt_es '[' HL ']' + { B1 (0x0d|$1); } + + | addsub A ',' opt_es '[' HL '+' EXPR ']' + { B1 (0x0e|$1); O1 ($8); } + + | addsub A ',' opt_es '[' HL '+' B ']' + { B2 (0x61, 0x80|$1); } + + | addsub A ',' opt_es '[' HL '+' C ']' + { B2 (0x61, 0x82|$1); } + + + + | addsub opt_es '!' EXPR ',' '#' EXPR + { if ($1 != 0x40) + { rl78_error ("Only CMP takes these operands"); } + else + { B1 (0x00|$1); O2 ($4); O1 ($7); } + } + +/* ---------------------------------------------------------------------- */ + + | addsubw AX ',' '#' EXPR + { B1 (0x04|$1); O2 ($5); } + + | addsubw AX ',' regw + { B1 (0x01|$1); F ($4, 5, 2); } + + | addsubw AX ',' EXPR {SA($4)} + { B1 (0x06|$1); O1 ($4); } + + | addsubw AX ',' opt_es '!' EXPR + { B1 (0x02|$1); O2 ($6); } + + | addsubw AX ',' opt_es '[' HL '+' EXPR ']' + { B2 (0x61, 0x09|$1); O1 ($8); } + + | addsubw AX ',' opt_es '[' HL ']' + { B4 (0x61, 0x09|$1, 0, 0); } + + | addsubw SP ',' '#' EXPR + { B1 ($1 ? 0x20 : 0x10); O1 ($5); + if ($1 == 0x40) + rl78_error ("CMPW SP,#imm not allowed"); + } + +/* ---------------------------------------------------------------------- */ + + | andor1 CY ',' sfr '.' EXPR {Bit($6)} + { B3 (0x71, 0x08|$1, $4); FE ($6, 9, 3); } + + | andor1 CY ',' EXPR '.' EXPR {Bit($6)} + { if (expr_is_sfr ($4)) + { B2 (0x71, 0x08|$1); FE ($6, 9, 3); O1 ($4); } + else if (expr_is_saddr ($4)) + { B2 (0x71, 0x00|$1); FE ($6, 9, 3); O1 ($4); } + else + NOT_SFR_OR_SADDR; + } + + | andor1 CY ',' A '.' EXPR {Bit($6)} + { B2 (0x71, 0x88|$1); FE ($6, 9, 3); } + + | andor1 CY ',' opt_es '[' HL ']' '.' EXPR {Bit($9)} + { B2 (0x71, 0x80|$1); FE ($9, 9, 3); } + +/* ---------------------------------------------------------------------- */ + + | BC '$' EXPR + { B1 (0xdc); PC1 ($3); } + + | BNC '$' EXPR + { B1 (0xde); PC1 ($3); } + + | BZ '$' EXPR + { B1 (0xdd); PC1 ($3); } + + | BNZ '$' EXPR + { B1 (0xdf); PC1 ($3); } + + | BH '$' EXPR + { B2 (0x61, 0xc3); PC1 ($3); } + + | BNH '$' EXPR + { B2 (0x61, 0xd3); PC1 ($3); } + +/* ---------------------------------------------------------------------- */ + + | bt_bf sfr '.' EXPR ',' '$' EXPR + { B3 (0x31, 0x80|$1, $2); FE ($4, 9, 3); PC1 ($7); } + + | bt_bf EXPR '.' EXPR ',' '$' EXPR + { if (expr_is_sfr ($2)) + { B2 (0x31, 0x80|$1); FE ($4, 9, 3); O1 ($2); PC1 ($7); } + else if (expr_is_saddr ($2)) + { B2 (0x31, 0x00|$1); FE ($4, 9, 3); O1 ($2); PC1 ($7); } + else + NOT_SFR_OR_SADDR; + } + + | bt_bf A '.' EXPR ',' '$' EXPR + { B2 (0x31, 0x01|$1); FE ($4, 9, 3); PC1 ($7); } + + | bt_bf opt_es '[' HL ']' '.' EXPR ',' '$' EXPR + { B2 (0x31, 0x81|$1); FE ($7, 9, 3); PC1 ($10); } + +/* ---------------------------------------------------------------------- */ + + | BR AX + { B2 (0x61, 0xcb); } + + | BR '$' EXPR + { B1 (0xef); PC1 ($3); } + + | BR '$' '!' EXPR + { B1 (0xee); PC2 ($4); } + + | BR '!' EXPR + { B1 (0xed); O2 ($3); } + + | BR '!' '!' EXPR + { B1 (0xec); O3 ($4); } + +/* ---------------------------------------------------------------------- */ + + | BRK + { B2 (0x61, 0xcc); } + + | BRK1 + { B1 (0xff); } + +/* ---------------------------------------------------------------------- */ + + | CALL regw + { B2 (0x61, 0xca); F ($2, 10, 2); } + + | CALL '$' '!' EXPR + { B1 (0xfe); PC2 ($4); } + + | CALL '!' EXPR + { B1 (0xfd); O2 ($3); } + + | CALL '!' '!' EXPR + { B1 (0xfc); O3 ($4); } + + | CALLT '[' EXPR ']' + { if ($3.X_op != O_constant) + rl78_error ("CALLT requires a numeric address"); + else + { + int i = $3.X_add_number; + if (i < 0x80 || i > 0xbe) + rl78_error ("CALLT address not 0x80..0xbe"); + else if (i & 1) + rl78_error ("CALLT address not even"); + else + { + B2 (0x61, 0x84); + F ((i >> 1) & 7, 9, 3); + F ((i >> 4) & 7, 14, 2); + } + } + } + +/* ---------------------------------------------------------------------- */ + + | setclr1 CY + { B2 (0x71, $1 ? 0x88 : 0x80); } + + | setclr1 sfr '.' EXPR + { B3 (0x71, 0x0a|$1, $2); FE ($4, 9, 3); } + + | setclr1 EXPR '.' EXPR + { if (expr_is_sfr ($2)) + { B2 (0x71, 0x0a|$1); FE ($4, 9, 3); O1 ($2); } + else if (expr_is_saddr ($2)) + { B2 (0x71, 0x02|$1); FE ($4, 9, 3); O1 ($2); } + else + NOT_SFR_OR_SADDR; + } + + | setclr1 A '.' EXPR + { B2 (0x71, 0x8a|$1); FE ($4, 9, 3); } + + | setclr1 opt_es '!' EXPR '.' EXPR + { B2 (0x71, 0x00+$1*0x08); FE ($6, 9, 3); O2 ($4); } + + | setclr1 opt_es '[' HL ']' '.' EXPR + { B2 (0x71, 0x82|$1); FE ($7, 9, 3); } + +/* ---------------------------------------------------------------------- */ + + | oneclrb A + { B1 (0xe1|$1); } + | oneclrb X + { B1 (0xe0|$1); } + | oneclrb B + { B1 (0xe3|$1); } + | oneclrb C + { B1 (0xe2|$1); } + + | oneclrb EXPR {SA($2)} + { B1 (0xe4|$1); O1 ($2); } + + | oneclrb opt_es '!' EXPR + { B1 (0xe5|$1); O2 ($4); } + +/* ---------------------------------------------------------------------- */ + + | oneclrw AX + { B1 (0xe6|$1); } + | oneclrw BC + { B1 (0xe7|$1); } + +/* ---------------------------------------------------------------------- */ + + | CMP0 A + { B1 (0xd1); } + + | CMP0 X + { B1 (0xd0); } + + | CMP0 B + { B1 (0xd3); } + + | CMP0 C + { B1 (0xd2); } + + | CMP0 EXPR {SA($2)} + { B1 (0xd4); O1 ($2); } + + | CMP0 opt_es '!' EXPR + { B1 (0xd5); O2 ($4); } + +/* ---------------------------------------------------------------------- */ + + | CMPS X ',' opt_es '[' HL '+' EXPR ']' + { B2 (0x61, 0xde); O1 ($8); } + +/* ---------------------------------------------------------------------- */ + + | incdec regb + { B1 (0x80|$1); F ($2, 5, 3); } + + | incdec EXPR {SA($2)} + { B1 (0xa4|$1); O1 ($2); } + | incdec '!' EXPR + { B1 (0xa0|$1); O2 ($3); } + | incdec ES ':' '!' EXPR + { B2 (0x11, 0xa0|$1); O2 ($5); } + | incdec '[' HL '+' EXPR ']' + { B2 (0x61, 0x59+$1); O1 ($5); } + | incdec ES ':' '[' HL '+' EXPR ']' + { B3 (0x11, 0x61, 0x59+$1); O1 ($7); } + +/* ---------------------------------------------------------------------- */ + + | incdecw regw + { B1 (0xa1|$1); F ($2, 5, 2); } + + | incdecw EXPR {SA($2)} + { B1 (0xa6|$1); O1 ($2); } + + | incdecw opt_es '!' EXPR + { B1 (0xa2|$1); O2 ($4); } + + | incdecw opt_es '[' HL '+' EXPR ']' + { B2 (0x61, 0x79+$1); O1 ($6); } + +/* ---------------------------------------------------------------------- */ + + | DI + { B3 (0x71, 0x7b, 0xfa); } + + | EI + { B3 (0x71, 0x7a, 0xfa); } + +/* ---------------------------------------------------------------------- */ + + | MULHU + { B3 (0xce, 0xfb, 0x01); } + + | MULH + { B3 (0xce, 0xfb, 0x02); } + + | MULU X + { B1 (0xd6); } + + | DIVHU + { B3 (0xce, 0xfb, 0x03); } + + | DIVWU + { B3 (0xce, 0xfb, 0x04); } + + | MACHU + { B3 (0xce, 0xfb, 0x05); } + + | MACH + { B3 (0xce, 0xfb, 0x06); } + +/* ---------------------------------------------------------------------- */ + + | HALT + { B2 (0x61, 0xed); } + +/* ---------------------------------------------------------------------- */ +/* Note that opt_es is included even when it's not an option, to avoid + shift/reduce conflicts. The NOT_ES macro produces an error if ES: + is given by the user. */ + + | MOV A ',' '#' EXPR + { B1 (0x51); O1 ($5); } + | MOV regb_na ',' '#' EXPR + { B1 (0x50); F($2, 5, 3); O1 ($5); } + + | MOV sfr ',' '#' EXPR + { if ($2 != 0xfd) + { B2 (0xce, $2); O1 ($5); } + else + { B1 (0x41); O1 ($5); } + } + + | MOV opt_es EXPR ',' '#' EXPR {NOT_ES} + { if (expr_is_sfr ($3)) + { B1 (0xce); O1 ($3); O1 ($6); } + else if (expr_is_saddr ($3)) + { B1 (0xcd); O1 ($3); O1 ($6); } + else + NOT_SFR_OR_SADDR; + } + + | MOV '!' EXPR ',' '#' EXPR + { B1 (0xcf); O2 ($3); O1 ($6); } + + | MOV ES ':' '!' EXPR ',' '#' EXPR + { B2 (0x11, 0xcf); O2 ($5); O1 ($8); } + + | MOV regb_na ',' A + { B1 (0x70); F ($2, 5, 3); } + + | MOV A ',' regb_na + { B1 (0x60); F ($4, 5, 3); } + + | MOV opt_es EXPR ',' A {NOT_ES} + { if (expr_is_sfr ($3)) + { B1 (0x9e); O1 ($3); } + else if (expr_is_saddr ($3)) + { B1 (0x9d); O1 ($3); } + else + NOT_SFR_OR_SADDR; + } + + | MOV A ',' opt_es '!' EXPR + { B1 (0x8f); O2 ($6); } + + | MOV '!' EXPR ',' A + { B1 (0x9f); O2 ($3); } + + | MOV ES ':' '!' EXPR ',' A + { B2 (0x11, 0x9f); O2 ($5); } + + | MOV regb_na ',' opt_es '!' EXPR + { B1 (0xc9|reg_xbc($2)); O2 ($6); } + + | MOV A ',' opt_es EXPR {NOT_ES} + { if (expr_is_saddr ($5)) + { B1 (0x8d); O1 ($5); } + else if (expr_is_sfr ($5)) + { B1 (0x8e); O1 ($5); } + else + NOT_SFR_OR_SADDR; + } + + | MOV regb_na ',' opt_es EXPR {SA($5)} {NOT_ES} + { B1 (0xc8|reg_xbc($2)); O1 ($5); } + + | MOV A ',' sfr + { B2 (0x8e, $4); } + + | MOV sfr ',' regb + { if ($4 != 1) + rl78_error ("Only A allowed here"); + else + { B2 (0x9e, $2); } + } + + | MOV sfr ',' opt_es EXPR {SA($5)} {NOT_ES} + { if ($2 != 0xfd) + rl78_error ("Only ES allowed here"); + else + { B2 (0x61, 0xb8); O1 ($5); } + } + + | MOV A ',' opt_es '[' DE ']' + { B1 (0x89); } + + | MOV opt_es '[' DE ']' ',' A + { B1 (0x99); } + + | MOV opt_es '[' DE '+' EXPR ']' ',' '#' EXPR + { B1 (0xca); O1 ($6); O1 ($10); } + + | MOV A ',' opt_es '[' DE '+' EXPR ']' + { B1 (0x8a); O1 ($8); } + + | MOV opt_es '[' DE '+' EXPR ']' ',' A + { B1 (0x9a); O1 ($6); } + + | MOV A ',' opt_es '[' HL ']' + { B1 (0x8b); } + + | MOV opt_es '[' HL ']' ',' A + { B1 (0x9b); } + + | MOV opt_es '[' HL '+' EXPR ']' ',' '#' EXPR + { B1 (0xcc); O1 ($6); O1 ($10); } + + | MOV A ',' opt_es '[' HL '+' EXPR ']' + { B1 (0x8c); O1 ($8); } + + | MOV opt_es '[' HL '+' EXPR ']' ',' A + { B1 (0x9c); O1 ($6); } + + | MOV A ',' opt_es '[' HL '+' B ']' + { B2 (0x61, 0xc9); } + + | MOV opt_es '[' HL '+' B ']' ',' A + { B2 (0x61, 0xd9); } + + | MOV A ',' opt_es '[' HL '+' C ']' + { B2 (0x61, 0xe9); } + + | MOV opt_es '[' HL '+' C ']' ',' A + { B2 (0x61, 0xf9); } + + | MOV opt_es EXPR '[' B ']' ',' '#' EXPR + { B1 (0x19); O2 ($3); O1 ($9); } + + | MOV A ',' opt_es EXPR '[' B ']' + { B1 (0x09); O2 ($5); } + + | MOV opt_es EXPR '[' B ']' ',' A + { B1 (0x18); O2 ($3); } + + | MOV opt_es EXPR '[' C ']' ',' '#' EXPR + { B1 (0x38); O2 ($3); O1 ($9); } + + | MOV A ',' opt_es EXPR '[' C ']' + { B1 (0x29); O2 ($5); } + + | MOV opt_es EXPR '[' C ']' ',' A + { B1 (0x28); O2 ($3); } + + | MOV opt_es EXPR '[' BC ']' ',' '#' EXPR + { B1 (0x39); O2 ($3); O1 ($9); } + + | MOV opt_es '[' BC ']' ',' '#' EXPR + { B3 (0x39, 0, 0); O1 ($8); } + + | MOV A ',' opt_es EXPR '[' BC ']' + { B1 (0x49); O2 ($5); } + + | MOV A ',' opt_es '[' BC ']' + { B3 (0x49, 0, 0); } + + | MOV opt_es EXPR '[' BC ']' ',' A + { B1 (0x48); O2 ($3); } + + | MOV opt_es '[' BC ']' ',' A + { B3 (0x48, 0, 0); } + + | MOV opt_es '[' SP '+' EXPR ']' ',' '#' EXPR {NOT_ES} + { B1 (0xc8); O1 ($6); O1 ($10); } + + | MOV opt_es '[' SP ']' ',' '#' EXPR {NOT_ES} + { B2 (0xc8, 0); O1 ($8); } + + | MOV A ',' opt_es '[' SP '+' EXPR ']' {NOT_ES} + { B1 (0x88); O1 ($8); } + + | MOV A ',' opt_es '[' SP ']' {NOT_ES} + { B2 (0x88, 0); } + + | MOV opt_es '[' SP '+' EXPR ']' ',' A {NOT_ES} + { B1 (0x98); O1 ($6); } + + | MOV opt_es '[' SP ']' ',' A {NOT_ES} + { B2 (0x98, 0); } + +/* ---------------------------------------------------------------------- */ + + | MOV1 CY ',' EXPR '.' EXPR + { if (expr_is_saddr ($4)) + { B2 (0x71, 0x04); FE ($6, 9, 3); O1 ($4); } + else if (expr_is_sfr ($4)) + { B2 (0x71, 0x0c); FE ($6, 9, 3); O1 ($4); } + else + NOT_SFR_OR_SADDR; + } + + | MOV1 CY ',' A '.' EXPR + { B2 (0x71, 0x8c); FE ($6, 9, 3); } + + | MOV1 CY ',' sfr '.' EXPR + { B3 (0x71, 0x0c, $4); FE ($6, 9, 3); } + + | MOV1 CY ',' opt_es '[' HL ']' '.' EXPR + { B2 (0x71, 0x84); FE ($9, 9, 3); } + + | MOV1 EXPR '.' EXPR ',' CY + { if (expr_is_saddr ($2)) + { B2 (0x71, 0x01); FE ($4, 9, 3); O1 ($2); } + else if (expr_is_sfr ($2)) + { B2 (0x71, 0x09); FE ($4, 9, 3); O1 ($2); } + else + NOT_SFR_OR_SADDR; + } + + | MOV1 A '.' EXPR ',' CY + { B2 (0x71, 0x89); FE ($4, 9, 3); } + + | MOV1 sfr '.' EXPR ',' CY + { B3 (0x71, 0x09, $2); FE ($4, 9, 3); } + + | MOV1 opt_es '[' HL ']' '.' EXPR ',' CY + { B2 (0x71, 0x81); FE ($7, 9, 3); } + +/* ---------------------------------------------------------------------- */ + + | MOVS opt_es '[' HL '+' EXPR ']' ',' X + { B2 (0x61, 0xce); O1 ($6); } + +/* ---------------------------------------------------------------------- */ + + | MOVW AX ',' '#' EXPR + { B1 (0x30); O2 ($5); } + + | MOVW regw_na ',' '#' EXPR + { B1 (0x30); F ($2, 5, 2); O2 ($5); } + + | MOVW opt_es EXPR ',' '#' EXPR {NOT_ES} + { if (expr_is_saddr ($3)) + { B1 (0xc9); O1 ($3); O2 ($6); } + else if (expr_is_sfr ($3)) + { B1 (0xcb); O1 ($3); O2 ($6); } + else + NOT_SFR_OR_SADDR; + } + + | MOVW AX ',' opt_es EXPR {NOT_ES} + { if (expr_is_saddr ($5)) + { B1 (0xad); O1 ($5); WA($5); } + else if (expr_is_sfr ($5)) + { B1 (0xae); O1 ($5); WA($5); } + else + NOT_SFR_OR_SADDR; + } + + | MOVW opt_es EXPR ',' AX {NOT_ES} + { if (expr_is_saddr ($3)) + { B1 (0xbd); O1 ($3); WA($3); } + else if (expr_is_sfr ($3)) + { B1 (0xbe); O1 ($3); WA($3); } + else + NOT_SFR_OR_SADDR; + } + + | MOVW AX ',' regw_na + { B1 (0x11); F ($4, 5, 2); } + + | MOVW regw_na ',' AX + { B1 (0x10); F ($2, 5, 2); } + + | MOVW AX ',' opt_es '!' EXPR + { B1 (0xaf); O2 ($6); WA($6); } + + | MOVW opt_es '!' EXPR ',' AX + { B1 (0xbf); O2 ($4); WA($4); } + + | MOVW AX ',' opt_es '[' DE ']' + { B1 (0xa9); } + + | MOVW opt_es '[' DE ']' ',' AX + { B1 (0xb9); } + + | MOVW AX ',' opt_es '[' DE '+' EXPR ']' + { B1 (0xaa); O1 ($8); } + + | MOVW opt_es '[' DE '+' EXPR ']' ',' AX + { B1 (0xba); O1 ($6); } + + | MOVW AX ',' opt_es '[' HL ']' + { B1 (0xab); } + + | MOVW opt_es '[' HL ']' ',' AX + { B1 (0xbb); } + + | MOVW AX ',' opt_es '[' HL '+' EXPR ']' + { B1 (0xac); O1 ($8); } + + | MOVW opt_es '[' HL '+' EXPR ']' ',' AX + { B1 (0xbc); O1 ($6); } + + | MOVW AX ',' opt_es EXPR '[' B ']' + { B1 (0x59); O2 ($5); } + + | MOVW opt_es EXPR '[' B ']' ',' AX + { B1 (0x58); O2 ($3); } + + | MOVW AX ',' opt_es EXPR '[' C ']' + { B1 (0x69); O2 ($5); } + + | MOVW opt_es EXPR '[' C ']' ',' AX + { B1 (0x68); O2 ($3); } + + | MOVW AX ',' opt_es EXPR '[' BC ']' + { B1 (0x79); O2 ($5); } + + | MOVW AX ',' opt_es '[' BC ']' + { B3 (0x79, 0, 0); } + + | MOVW opt_es EXPR '[' BC ']' ',' AX + { B1 (0x78); O2 ($3); } + + | MOVW opt_es '[' BC ']' ',' AX + { B3 (0x78, 0, 0); } + + | MOVW AX ',' opt_es '[' SP '+' EXPR ']' {NOT_ES} + { B1 (0xa8); O1 ($8); WA($8);} + + | MOVW AX ',' opt_es '[' SP ']' {NOT_ES} + { B2 (0xa8, 0); } + + | MOVW opt_es '[' SP '+' EXPR ']' ',' AX {NOT_ES} + { B1 (0xb8); O1 ($6); WA($6); } + + | MOVW opt_es '[' SP ']' ',' AX {NOT_ES} + { B2 (0xb8, 0); } + + | MOVW regw_na ',' EXPR {SA($4)} + { B1 (0xca); F ($2, 2, 2); O1 ($4); WA($4); } + + | MOVW regw_na ',' opt_es '!' EXPR + { B1 (0xcb); F ($2, 2, 2); O2 ($6); WA($6); } + + | MOVW SP ',' '#' EXPR + { B2 (0xcb, 0xf8); O2 ($5); } + + | MOVW SP ',' AX + { B2 (0xbe, 0xf8); } + + | MOVW AX ',' SP + { B2 (0xae, 0xf8); } + + | MOVW regw_na ',' SP + { B3 (0xcb, 0xf8, 0xff); F ($2, 2, 2); } + +/* ---------------------------------------------------------------------- */ + + | NOP + { B1 (0x00); } + +/* ---------------------------------------------------------------------- */ + + | POP regw + { B1 (0xc0); F ($2, 5, 2); } + + | POP PSW + { B2 (0x61, 0xcd); }; + + | PUSH regw + { B1 (0xc1); F ($2, 5, 2); } + + | PUSH PSW + { B2 (0x61, 0xdd); }; + +/* ---------------------------------------------------------------------- */ + + | RET + { B1 (0xd7); } + + | RETI + { B2 (0x61, 0xfc); } + + | RETB + { B2 (0x61, 0xec); } + +/* ---------------------------------------------------------------------- */ + + | ROL A ',' EXPR + { if (check_expr_is_const ($4, 1, 1)) + { B2 (0x61, 0xeb); } + } + + | ROLC A ',' EXPR + { if (check_expr_is_const ($4, 1, 1)) + { B2 (0x61, 0xdc); } + } + + | ROLWC AX ',' EXPR + { if (check_expr_is_const ($4, 1, 1)) + { B2 (0x61, 0xee); } + } + + | ROLWC BC ',' EXPR + { if (check_expr_is_const ($4, 1, 1)) + { B2 (0x61, 0xfe); } + } + + | ROR A ',' EXPR + { if (check_expr_is_const ($4, 1, 1)) + { B2 (0x61, 0xdb); } + } + + | RORC A ',' EXPR + { if (check_expr_is_const ($4, 1, 1)) + { B2 (0x61, 0xfb);} + } + +/* ---------------------------------------------------------------------- */ + + | SAR A ',' EXPR + { if (check_expr_is_const ($4, 1, 7)) + { B2 (0x31, 0x0b); FE ($4, 9, 3); } + } + + | SARW AX ',' EXPR + { if (check_expr_is_const ($4, 1, 15)) + { B2 (0x31, 0x0f); FE ($4, 8, 4); } + } + +/* ---------------------------------------------------------------------- */ + + | SEL RB0 + { B2 (0x61, 0xcf); } + + | SEL RB1 + { B2 (0x61, 0xdf); } + + | SEL RB2 + { B2 (0x61, 0xef); } + + | SEL RB3 + { B2 (0x61, 0xff); } + +/* ---------------------------------------------------------------------- */ + + | SHL A ',' EXPR + { if (check_expr_is_const ($4, 1, 7)) + { B2 (0x31, 0x09); FE ($4, 9, 3); } + } + + | SHL B ',' EXPR + { if (check_expr_is_const ($4, 1, 7)) + { B2 (0x31, 0x08); FE ($4, 9, 3); } + } + + | SHL C ',' EXPR + { if (check_expr_is_const ($4, 1, 7)) + { B2 (0x31, 0x07); FE ($4, 9, 3); } + } + + | SHLW AX ',' EXPR + { if (check_expr_is_const ($4, 1, 15)) + { B2 (0x31, 0x0d); FE ($4, 8, 4); } + } + + | SHLW BC ',' EXPR + { if (check_expr_is_const ($4, 1, 15)) + { B2 (0x31, 0x0c); FE ($4, 8, 4); } + } + +/* ---------------------------------------------------------------------- */ + + | SHR A ',' EXPR + { if (check_expr_is_const ($4, 1, 7)) + { B2 (0x31, 0x0a); FE ($4, 9, 3); } + } + + | SHRW AX ',' EXPR + { if (check_expr_is_const ($4, 1, 15)) + { B2 (0x31, 0x0e); FE ($4, 8, 4); } + } + +/* ---------------------------------------------------------------------- */ + + | SKC + { B2 (0x61, 0xc8); } + + | SKH + { B2 (0x61, 0xe3); } + + | SKNC + { B2 (0x61, 0xd8); } + + | SKNH + { B2 (0x61, 0xf3); } + + | SKNZ + { B2 (0x61, 0xf8); } + + | SKZ + { B2 (0x61, 0xe8); } + +/* ---------------------------------------------------------------------- */ + + | STOP + { B2 (0x61, 0xfd); } + +/* ---------------------------------------------------------------------- */ + + | XCH A ',' regb_na + { if ($4 == 0) /* X */ + { B1 (0x08); } + else + { B2 (0x61, 0x88); F ($4, 13, 3); } + } + + | XCH A ',' opt_es '!' EXPR + { B2 (0x61, 0xaa); O2 ($6); } + + | XCH A ',' opt_es '[' DE ']' + { B2 (0x61, 0xae); } + + | XCH A ',' opt_es '[' DE '+' EXPR ']' + { B2 (0x61, 0xaf); O1 ($8); } + + | XCH A ',' opt_es '[' HL ']' + { B2 (0x61, 0xac); } + + | XCH A ',' opt_es '[' HL '+' EXPR ']' + { B2 (0x61, 0xad); O1 ($8); } + + | XCH A ',' opt_es '[' HL '+' B ']' + { B2 (0x61, 0xb9); } + + | XCH A ',' opt_es '[' HL '+' C ']' + { B2 (0x61, 0xa9); } + + | XCH A ',' EXPR + { if (expr_is_sfr ($4)) + { B2 (0x61, 0xab); O1 ($4); } + else if (expr_is_saddr ($4)) + { B2 (0x61, 0xa8); O1 ($4); } + else + NOT_SFR_OR_SADDR; + } + +/* ---------------------------------------------------------------------- */ + + | XCHW AX ',' regw_na + { B1 (0x31); F ($4, 5, 2); } + +/* ---------------------------------------------------------------------- */ + + ; /* end of statement */ + +/* ---------------------------------------------------------------------- */ + +opt_es : /* nothing */ + | ES ':' + { rl78_prefix (0x11); } + ; + +regb : X { $$ = 0; } + | A { $$ = 1; } + | C { $$ = 2; } + | B { $$ = 3; } + | E { $$ = 4; } + | D { $$ = 5; } + | L { $$ = 6; } + | H { $$ = 7; } + ; + +regb_na : X { $$ = 0; } + | C { $$ = 2; } + | B { $$ = 3; } + | E { $$ = 4; } + | D { $$ = 5; } + | L { $$ = 6; } + | H { $$ = 7; } + ; + +regw : AX { $$ = 0; } + | BC { $$ = 1; } + | DE { $$ = 2; } + | HL { $$ = 3; } + ; + +regw_na : BC { $$ = 1; } + | DE { $$ = 2; } + | HL { $$ = 3; } + ; + +sfr : SPL { $$ = 0xf8; } + | SPH { $$ = 0xf9; } + | PSW { $$ = 0xfa; } + | CS { $$ = 0xfc; } + | ES { $$ = 0xfd; } + | PMC { $$ = 0xfe; } + | MEM { $$ = 0xff; } + ; + +/* ---------------------------------------------------------------------- */ +/* Shortcuts for groups of opcodes with common encodings. */ + +addsub : ADD { $$ = 0x00; } + | ADDC { $$ = 0x10; } + | SUB { $$ = 0x20; } + | SUBC { $$ = 0x30; } + | CMP { $$ = 0x40; } + | AND_ { $$ = 0x50; } + | OR { $$ = 0x60; } + | XOR { $$ = 0x70; } + ; + +addsubw : ADDW { $$ = 0x00; } + | SUBW { $$ = 0x20; } + | CMPW { $$ = 0x40; } + ; + +andor1 : AND1 { $$ = 0x05; } + | OR1 { $$ = 0x06; } + | XOR1 { $$ = 0x07; } + ; + +bt_bf : BT { $$ = 0x02; } + | BF { $$ = 0x04; } + | BTCLR { $$ = 0x00; } + ; + +setclr1 : SET1 { $$ = 0; } + | CLR1 { $$ = 1; } + ; + +oneclrb : ONEB { $$ = 0x00; } + | CLRB { $$ = 0x10; } + ; + +oneclrw : ONEW { $$ = 0x00; } + | CLRW { $$ = 0x10; } + ; + +incdec : INC { $$ = 0x00; } + | DEC { $$ = 0x10; } + ; + +incdecw : INCW { $$ = 0x00; } + | DECW { $$ = 0x10; } + ; + +%% +/* ====================================================================== */ + +static struct +{ + const char * string; + int token; + int val; +} +token_table[] = +{ + { "r0", X, 0 }, + { "r1", A, 1 }, + { "r2", C, 2 }, + { "r3", B, 3 }, + { "r4", E, 4 }, + { "r5", D, 5 }, + { "r6", L, 6 }, + { "r7", H, 7 }, + { "x", X, 0 }, + { "a", A, 1 }, + { "c", C, 2 }, + { "b", B, 3 }, + { "e", E, 4 }, + { "d", D, 5 }, + { "l", L, 6 }, + { "h", H, 7 }, + + { "rp0", AX, 0 }, + { "rp1", BC, 1 }, + { "rp2", DE, 2 }, + { "rp3", HL, 3 }, + { "ax", AX, 0 }, + { "bc", BC, 1 }, + { "de", DE, 2 }, + { "hl", HL, 3 }, + + { "RB0", RB0, 0 }, + { "RB1", RB1, 1 }, + { "RB2", RB2, 2 }, + { "RB3", RB3, 3 }, + + { "sp", SP, 0 }, + { "cy", CY, 0 }, + + { "spl", SPL, 0xf8 }, + { "sph", SPH, 0xf9 }, + { "psw", PSW, 0xfa }, + { "cs", CS, 0xfc }, + { "es", ES, 0xfd }, + { "pmc", PMC, 0xfe }, + { "mem", MEM, 0xff }, + + { ".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(ADD), + OPC(ADDC), + OPC(ADDW), + { "and", AND_, IS_OPCODE }, + OPC(AND1), + OPC(BC), + OPC(BF), + OPC(BH), + OPC(BNC), + OPC(BNH), + OPC(BNZ), + OPC(BR), + OPC(BRK), + OPC(BRK1), + OPC(BT), + OPC(BTCLR), + OPC(BZ), + OPC(CALL), + OPC(CALLT), + OPC(CLR1), + OPC(CLRB), + OPC(CLRW), + OPC(CMP), + OPC(CMP0), + OPC(CMPS), + OPC(CMPW), + OPC(DEC), + OPC(DECW), + OPC(DI), + OPC(DIVHU), + OPC(DIVWU), + OPC(EI), + OPC(HALT), + OPC(INC), + OPC(INCW), + OPC(MACH), + OPC(MACHU), + OPC(MOV), + OPC(MOV1), + OPC(MOVS), + OPC(MOVW), + OPC(MULH), + OPC(MULHU), + OPC(MULU), + OPC(NOP), + OPC(ONEB), + OPC(ONEW), + OPC(OR), + OPC(OR1), + OPC(POP), + OPC(PUSH), + OPC(RET), + OPC(RETI), + OPC(RETB), + OPC(ROL), + OPC(ROLC), + OPC(ROLWC), + OPC(ROR), + OPC(RORC), + OPC(SAR), + OPC(SARW), + OPC(SEL), + OPC(SET1), + OPC(SHL), + OPC(SHLW), + OPC(SHR), + OPC(SHRW), + OPC(SKC), + OPC(SKH), + OPC(SKNC), + OPC(SKNH), + OPC(SKNZ), + OPC(SKZ), + OPC(STOP), + OPC(SUB), + OPC(SUBC), + OPC(SUBW), + OPC(XCH), + OPC(XCHW), + OPC(XOR), + OPC(XOR1), +}; + +#define NUM_TOKENS (sizeof (token_table) / sizeof (token_table[0])) + +void +rl78_lex_init (char * beginning, char * ending) +{ + rl78_init_start = beginning; + rl78_lex_start = beginning; + rl78_lex_end = ending; + rl78_in_brackets = 0; + rl78_last_token = 0; + + setbuf (stdout, 0); +} + +static int +rl78_lex (void) +{ + /*unsigned int ci;*/ + char * save_input_pointer; + + while (ISSPACE (*rl78_lex_start) + && rl78_lex_start != rl78_lex_end) + rl78_lex_start ++; + + rl78_last_exp_start = rl78_lex_start; + + if (rl78_lex_start == rl78_lex_end) + return 0; + + if (ISALPHA (*rl78_lex_start) + || (*rl78_lex_start == '.' && ISALPHA (rl78_lex_start[1]))) + { + unsigned int i; + char * e; + char save; + + for (e = rl78_lex_start + 1; + e < rl78_lex_end && ISALNUM (*e); + e ++) + ; + save = *e; + *e = 0; + + for (i = 0; i < NUM_TOKENS; i++) + if (strcasecmp (rl78_lex_start, token_table[i].string) == 0 + && !(token_table[i].val == IS_OPCODE && rl78_last_token != 0) + && !(token_table[i].token == FLAG && !need_flag)) + { + rl78_lval.regno = token_table[i].val; + *e = save; + rl78_lex_start = e; + rl78_last_token = token_table[i].token; + return token_table[i].token; + } + *e = save; + } + + if (rl78_last_token == 0) + { + rl78_last_token = UNKNOWN_OPCODE; + return UNKNOWN_OPCODE; + } + + if (rl78_last_token == UNKNOWN_OPCODE) + return 0; + + if (*rl78_lex_start == '[') + rl78_in_brackets = 1; + if (*rl78_lex_start == ']') + rl78_in_brackets = 0; + + /* '.' is funny - the syntax includes it for bitfields, but only for + bitfields. We check for it specially so we can allow labels + with '.' in them. */ + + if (*rl78_lex_start == '.' + && ISDIGIT (rl78_lex_start[1]) + && (rl78_last_token == ']' + || rl78_last_token == A + || rl78_last_token == PSW + || rl78_last_token == EXPR)) + { + rl78_last_token = *rl78_lex_start; + return *rl78_lex_start ++; + } + + if ((rl78_in_brackets && *rl78_lex_start == '+') + || strchr ("[],#!$:", *rl78_lex_start)) + { + rl78_last_token = *rl78_lex_start; + return *rl78_lex_start ++; + } + + save_input_pointer = input_line_pointer; + input_line_pointer = rl78_lex_start; + rl78_lval.exp.X_md = 0; + expression (&rl78_lval.exp); + + rl78_lex_start = input_line_pointer; + input_line_pointer = save_input_pointer; + rl78_last_token = EXPR; + return EXPR; +} + +int +rl78_error (char * str) +{ + int len; + + len = rl78_last_exp_start - rl78_init_start; + + as_bad ("%s", rl78_init_start); + as_bad ("%*s^ %s", len, "", str); + return 0; +} + +static int +expr_is_sfr (expressionS exp) +{ + unsigned long v; + + if (exp.X_op != O_constant) + return 0; + + v = exp.X_add_number; + if (0xFFF00 <= v && v <= 0xFFFFF) + return 1; + return 0; +} + +static int +expr_is_saddr (expressionS exp) +{ + unsigned long v; + + if (exp.X_op != O_constant) + return 0; + + v = exp.X_add_number; + if (0xFFE20 <= v && v <= 0xFFF1F) + return 1; + return 0; +} + +static int +expr_is_word_aligned (expressionS exp) +{ + unsigned long v; + + if (exp.X_op != O_constant) + return 1; + + v = exp.X_add_number; + if (v & 1) + return 0; + return 1; + +} + +static void +check_expr_is_bit_index (expressionS exp) +{ + int val; + + if (exp.X_op != O_constant) + { + rl78_error (_("bit index must be a constant")); + return; + } + val = exp.X_add_number; + + if (val < 0 || val > 7) + rl78_error (_("rtsd size must be 0..7")); +} + +static int +exp_val (expressionS exp) +{ + if (exp.X_op != O_constant) + { + rl78_error (_("constant expected")); + return 0; + } + return exp.X_add_number; +} + +static int +check_expr_is_const (expressionS e, int vmin, int vmax) +{ + static char buf[100]; + if (e.X_op != O_constant + || e.X_add_number < vmin + || e.X_add_number > vmax) + { + if (vmin == vmax) + sprintf (buf, "%d expected here", vmin); + else + sprintf (buf, "%d..%d expected here", vmin, vmax); + rl78_error(buf); + return 0; + } + return 1; +} + + diff --git a/gas/config/tc-rl78.c b/gas/config/tc-rl78.c new file mode 100644 index 0000000..07a4cc8 --- /dev/null +++ b/gas/config/tc-rl78.c @@ -0,0 +1,701 @@ +/* tc-rl78.c -- Assembler for the Renesas RL78 + Copyright 2011 + 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 "struc-symbol.h" +#include "obstack.h" +#include "safe-ctype.h" +#include "dwarf2dbg.h" +#include "libbfd.h" +#include "elf/common.h" +#include "elf/rl78.h" +#include "rl78-defs.h" +#include "filenames.h" +#include "listing.h" +#include "sb.h" +#include "macro.h" + +const char comment_chars[] = ";"; +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +const char line_comment_chars[] = "#"; +const char line_separator_chars[] = "|"; + +const char EXP_CHARS[] = "eE"; +const char FLT_CHARS[] = "dD"; + +/*------------------------------------------------------------------*/ + +char * rl78_lex_start; +char * rl78_lex_end; + +typedef struct rl78_bytesT +{ + char prefix[1]; + int n_prefix; + char base[4]; + int n_base; + char ops[8]; + int n_ops; + struct + { + expressionS exp; + char offset; + char nbits; + char type; /* RL78REL_*. */ + int reloc; + fixS * fixP; + } fixups[2]; + int n_fixups; + struct + { + char type; + char field_pos; + char val_ofs; + } relax[2]; + int n_relax; + int link_relax; + fixS *link_relax_fixP; + char times_grown; + char times_shrank; +} rl78_bytesT; + +static rl78_bytesT rl78_bytes; + +static void +rl78_fixup (expressionS exp, int offsetbits, int nbits, int type) +{ + rl78_bytes.fixups[rl78_bytes.n_fixups].exp = exp; + rl78_bytes.fixups[rl78_bytes.n_fixups].offset = offsetbits; + rl78_bytes.fixups[rl78_bytes.n_fixups].nbits = nbits; + rl78_bytes.fixups[rl78_bytes.n_fixups].type = type; + rl78_bytes.fixups[rl78_bytes.n_fixups].reloc = exp.X_md; + rl78_bytes.n_fixups ++; +} + +#define rl78_field_fixup(exp, offset, nbits, type) \ + rl78_fixup (exp, offset + 8 * rl78_bytes.n_prefix), nbits, type) + +#define rl78_op_fixup(exp, offset, nbits, type) \ + rl78_fixup (exp, offset + 8 * (rl78_bytes.n_prefix + rl78_bytes.n_base), nbits, type) + +void +rl78_prefix (int p) +{ + rl78_bytes.prefix[0] = p; + rl78_bytes.n_prefix = 1; +} + +int +rl78_has_prefix () +{ + return rl78_bytes.n_prefix; +} + +void +rl78_base1 (int b1) +{ + rl78_bytes.base[0] = b1; + rl78_bytes.n_base = 1; +} + +void +rl78_base2 (int b1, int b2) +{ + rl78_bytes.base[0] = b1; + rl78_bytes.base[1] = b2; + rl78_bytes.n_base = 2; +} + +void +rl78_base3 (int b1, int b2, int b3) +{ + rl78_bytes.base[0] = b1; + rl78_bytes.base[1] = b2; + rl78_bytes.base[2] = b3; + rl78_bytes.n_base = 3; +} + +void +rl78_base4 (int b1, int b2, int b3, int b4) +{ + rl78_bytes.base[0] = b1; + rl78_bytes.base[1] = b2; + rl78_bytes.base[2] = b3; + rl78_bytes.base[3] = b4; + rl78_bytes.n_base = 4; +} + +#define F_PRECISION 2 + +void +rl78_op (expressionS exp, int nbytes, int type) +{ + int v = 0; + + if ((exp.X_op == O_constant || exp.X_op == O_big) + && type != RL78REL_PCREL) + { + if (exp.X_op == O_big && exp.X_add_number <= 0) + { + LITTLENUM_TYPE w[2]; + char * ip = rl78_bytes.ops + rl78_bytes.n_ops; + + gen_to_words (w, F_PRECISION, 8); + ip[3] = w[0] >> 8; + ip[2] = w[0]; + ip[1] = w[1] >> 8; + ip[0] = w[1]; + rl78_bytes.n_ops += 4; + } + else + { + v = exp.X_add_number; + while (nbytes) + { + rl78_bytes.ops[rl78_bytes.n_ops++] =v & 0xff; + v >>= 8; + nbytes --; + } + } + } + else + { + rl78_op_fixup (exp, rl78_bytes.n_ops * 8, nbytes * 8, type); + memset (rl78_bytes.ops + rl78_bytes.n_ops, 0, nbytes); + rl78_bytes.n_ops += nbytes; + } +} + +/* This gets complicated when the field spans bytes, because fields + are numbered from the MSB of the first byte as zero, and bits are + stored LSB towards the LSB of the byte. Thus, a simple four-bit + insertion of 12 at position 4 of 0x00 yields: 0x0b. A three-bit + insertion of b'MXL at position 7 is like this: + + - - - - - - - - - - - - - - - - + M X L */ + +void +rl78_field (int val, int pos, int sz) +{ + int valm; + int bytep, bitp; + + if (sz > 0) + { + if (val < 0 || val >= (1 << sz)) + as_bad (_("Value %d doesn't fit in unsigned %d-bit field"), val, sz); + } + else + { + sz = - sz; + if (val < -(1 << (sz - 1)) || val >= (1 << (sz - 1))) + as_bad (_("Value %d doesn't fit in signed %d-bit field"), val, sz); + } + + /* This code points at 'M' in the above example. */ + bytep = pos / 8; + bitp = pos % 8; + + while (bitp + sz > 8) + { + int ssz = 8 - bitp; + int svalm; + + svalm = val >> (sz - ssz); + svalm = svalm & ((1 << ssz) - 1); + svalm = svalm << (8 - bitp - ssz); + gas_assert (bytep < rl78_bytes.n_base); + rl78_bytes.base[bytep] |= svalm; + + bitp = 0; + sz -= ssz; + bytep ++; + } + valm = val & ((1 << sz) - 1); + valm = valm << (8 - bitp - sz); + gas_assert (bytep < rl78_bytes.n_base); + rl78_bytes.base[bytep] |= valm; +} + +/*------------------------------------------------------------------*/ + +#define RL78_SHORTOPTS "" +const char * md_shortopts = RL78_SHORTOPTS; + +/* Assembler options. */ +struct option md_longopts[] = +{ + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof (md_longopts); + +int +md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED) +{ + return 0; +} + +void +md_show_usage (FILE * stream ATTRIBUTE_UNUSED) +{ +} + + +static void +s_bss (int ignore ATTRIBUTE_UNUSED) +{ + int temp; + + temp = get_absolute_expression (); + subseg_set (bss_section, (subsegT) temp); + demand_empty_rest_of_line (); +} + +/* The target specific pseudo-ops which we support. */ +const pseudo_typeS md_pseudo_table[] = +{ + /* Our "standard" pseudos. */ + { "double", float_cons, 'd' }, + { "bss", s_bss, 0 }, + { "3byte", cons, 3 }, + { "int", cons, 4 }, + { "word", cons, 4 }, + + /* End of list marker. */ + { NULL, NULL, 0 } +}; + +void +md_begin (void) +{ +} + +void +rl78_md_end (void) +{ +} + +/* Write a value out to the object file, using the appropriate endianness. */ +void +md_number_to_chars (char * buf, valueT val, int n) +{ + number_to_chars_littleendian (buf, val, n); +} + +static struct +{ + char * fname; + int reloc; +} +reloc_functions[] = +{ + { "lo16", BFD_RELOC_RL78_LO16 }, + { "hi16", BFD_RELOC_RL78_HI16 }, + { "hi8", BFD_RELOC_RL78_HI8 }, + { 0, 0 } +}; + +void +md_operand (expressionS * exp ATTRIBUTE_UNUSED) +{ + int reloc = 0; + int i; + + for (i = 0; reloc_functions[i].fname; i++) + { + int flen = strlen (reloc_functions[i].fname); + + if (input_line_pointer[0] == '%' + && strncasecmp (input_line_pointer + 1, reloc_functions[i].fname, flen) == 0 + && input_line_pointer[flen + 1] == '(') + { + reloc = reloc_functions[i].reloc; + input_line_pointer += flen + 2; + break; + } + } + if (reloc == 0) + return; + + expression (exp); + if (* input_line_pointer == ')') + input_line_pointer ++; + + exp->X_md = reloc; +} + +void +rl78_frag_init (fragS * fragP) +{ + fragP->tc_frag_data = 0; +} + +char * +md_atof (int type, char * litP, int * sizeP) +{ + return ieee_md_atof (type, litP, sizeP, target_big_endian); +} + +symbolS * +md_undefined_symbol (char * name ATTRIBUTE_UNUSED) +{ + return NULL; +} + +#define APPEND(B, N_B) \ + if (rl78_bytes.N_B) \ + { \ + memcpy (bytes + idx, rl78_bytes.B, rl78_bytes.N_B); \ + idx += rl78_bytes.N_B; \ + } + + +void +md_assemble (char * str) +{ + char * bytes; + fragS * frag_then = frag_now; + int idx = 0; + int i; + int rel; + expressionS *exp; + + /*printf("\033[32mASM: %s\033[0m\n", str);*/ + + dwarf2_emit_insn (0); + + memset (& rl78_bytes, 0, sizeof (rl78_bytes)); + + rl78_lex_init (str, str + strlen (str)); + + rl78_parse (); + + bytes = frag_more (rl78_bytes.n_prefix + rl78_bytes.n_base + rl78_bytes.n_ops); + frag_then = frag_now; + + APPEND (prefix, n_prefix); + APPEND (base, n_base); + APPEND (ops, n_ops); + + for (i = 0; i < rl78_bytes.n_fixups; i ++) + { + /* index: [nbytes][type] */ + static int reloc_map[5][4] = + { + { 0, 0 }, + { BFD_RELOC_8, BFD_RELOC_8_PCREL }, + { BFD_RELOC_16, BFD_RELOC_16_PCREL }, + { BFD_RELOC_24, BFD_RELOC_24_PCREL }, + { BFD_RELOC_32, BFD_RELOC_32_PCREL }, + }; + fixS * f; + + idx = rl78_bytes.fixups[i].offset / 8; + rel = reloc_map [rl78_bytes.fixups[i].nbits / 8][(int) rl78_bytes.fixups[i].type]; + + if (rl78_bytes.fixups[i].reloc) + rel = rl78_bytes.fixups[i].reloc; + + if (frag_then->tc_frag_data) + exp = & frag_then->tc_frag_data->fixups[i].exp; + else + exp = & rl78_bytes.fixups[i].exp; + + f = fix_new_exp (frag_then, + (char *) bytes + idx - frag_then->fr_literal, + rl78_bytes.fixups[i].nbits / 8, + exp, + rl78_bytes.fixups[i].type == RL78REL_PCREL ? 1 : 0, + rel); + if (frag_then->tc_frag_data) + frag_then->tc_frag_data->fixups[i].fixP = f; + } +} + +void +rl78_cons_fix_new (fragS * frag, + int where, + int size, + expressionS * exp) +{ + bfd_reloc_code_real_type type; + + switch (size) + { + case 1: + type = BFD_RELOC_8; + break; + case 2: + type = BFD_RELOC_16; + break; + case 3: + type = BFD_RELOC_24; + break; + case 4: + type = BFD_RELOC_32; + break; + default: + as_bad (_("unsupported constant size %d\n"), size); + return; + } + + if (exp->X_op == O_subtract && exp->X_op_symbol) + { + if (size != 4 && size != 2 && size != 1) + as_bad (_("difference of two symbols only supported with .long, .short, or .byte")); + else + type = BFD_RELOC_RL78_DIFF; + } + + fix_new_exp (frag, where, (int) size, exp, 0, type); +} + +/* No relaxation just yet */ +int +md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED) +{ + return 0; +} +arelent ** +tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) +{ + static arelent * reloc[8]; + int rp; + int is_opcode = 0; + + if (fixp->fx_r_type == BFD_RELOC_NONE) + { + reloc[0] = NULL; + return reloc; + } + + if (fixp->fx_subsy + && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) + { + fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy); + fixp->fx_subsy = NULL; + } + + reloc[0] = (arelent *) xmalloc (sizeof (arelent)); + reloc[0]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + * reloc[0]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc[0]->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc[0]->addend = fixp->fx_offset; + + if (fixp->fx_r_type == BFD_RELOC_RL78_32_OP + && fixp->fx_subsy) + { + fixp->fx_r_type = BFD_RELOC_RL78_DIFF; + is_opcode = 1; + } + +#define OPX(REL,SYM,ADD) \ + reloc[rp] = (arelent *) xmalloc (sizeof (arelent)); \ + reloc[rp]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); \ + reloc[rp]->howto = bfd_reloc_type_lookup (stdoutput, REL); \ + reloc[rp]->addend = ADD; \ + * reloc[rp]->sym_ptr_ptr = SYM; \ + reloc[rp]->address = fixp->fx_frag->fr_address + fixp->fx_where; \ + reloc[++rp] = NULL +#define OPSYM(SYM) OPX(BFD_RELOC_RL78_SYM, SYM, 0) +#define OPIMM(IMM) OPX(BFD_RELOC_RL78_SYM, abs_symbol.bsym, IMM) +#define OP(OP) OPX(BFD_RELOC_RL78_##OP, *reloc[0]->sym_ptr_ptr, 0) +#define SYM0() reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RL78_SYM) + + rp = 1; + + /* Certain BFD relocations cannot be translated directly into + a single (non-Red Hat) RL78 relocation, but instead need + multiple RL78 relocations - handle them here. */ + switch (fixp->fx_r_type) + { + case BFD_RELOC_RL78_DIFF: + SYM0 (); + OPSYM (symbol_get_bfdsym (fixp->fx_subsy)); + OP(OP_SUBTRACT); + + switch (fixp->fx_size) + { + case 1: + OP(ABS8); + break; + case 2: + OP (ABS16); + break; + case 4: + OP (ABS32); + break; + } + break; + + case BFD_RELOC_RL78_NEG32: + SYM0 (); + OP (OP_NEG); + OP (ABS32); + break; + + case BFD_RELOC_RL78_LO16: + SYM0 (); + OPIMM (0xffff); + OP (OP_AND); + OP (ABS16); + break; + + case BFD_RELOC_RL78_HI16: + SYM0 (); + OPIMM (16); + OP (OP_SHRA); + OP (ABS16); + break; + + case BFD_RELOC_RL78_HI8: + SYM0 (); + OPIMM (16); + OP (OP_SHRA); + OPIMM (0xff); + OP (OP_AND); + OP (ABS8); + break; + + default: + reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + reloc[1] = NULL; + break; + } + + return reloc; +} + +int +rl78_validate_fix_sub (struct fix * f) +{ + /* We permit the subtraction of two symbols in a few cases. */ + /* mov #sym1-sym2, R3 */ + if (f->fx_r_type == BFD_RELOC_RL78_32_OP) + return 1; + /* .long sym1-sym2 */ + if (f->fx_r_type == BFD_RELOC_RL78_DIFF + && ! f->fx_pcrel + && (f->fx_size == 4 || f->fx_size == 2 || f->fx_size == 1)) + return 1; + return 0; +} + +long +md_pcrel_from_section (fixS * fixP, segT sec) +{ + long rv; + + if (fixP->fx_addsy != NULL + && (! S_IS_DEFINED (fixP->fx_addsy) + || S_GET_SEGMENT (fixP->fx_addsy) != sec)) + /* The symbol is undefined (or is defined but not in this section). + Let the linker figure it out. */ + return 0; + + rv = fixP->fx_frag->fr_address + fixP->fx_where; + switch (fixP->fx_r_type) + { + case BFD_RELOC_8_PCREL: + rv += 1; + break; + case BFD_RELOC_16_PCREL: + rv += 2; + break; + default: + break; + } + return rv; +} + +void +md_apply_fix (struct fix * f ATTRIBUTE_UNUSED, + valueT * t ATTRIBUTE_UNUSED, + segT s ATTRIBUTE_UNUSED) +{ + char * op; + unsigned long val; + + if (f->fx_addsy && S_FORCE_RELOC (f->fx_addsy, 1)) + return; + if (f->fx_subsy && S_FORCE_RELOC (f->fx_subsy, 1)) + return; + + op = f->fx_frag->fr_literal + f->fx_where; + val = (unsigned long) * t; + + switch (f->fx_r_type) + { + case BFD_RELOC_NONE: + break; + + case BFD_RELOC_8: + case BFD_RELOC_8_PCREL: + op[0] = val; + break; + + case BFD_RELOC_16: + case BFD_RELOC_16_PCREL: + op[0] = val; + op[1] = val >> 8; + break; + + case BFD_RELOC_24: + op[0] = val; + op[1] = val >> 8; + op[2] = val >> 16; + break; + + case BFD_RELOC_32: + case BFD_RELOC_RL78_DIFF: + op[0] = val; + op[1] = val >> 8; + op[2] = val >> 16; + op[3] = val >> 24; + break; + + default: + as_bad (_("Unknown reloc in md_apply_fix: %s"), + bfd_get_reloc_code_name (f->fx_r_type)); + break; + } + + if (f->fx_addsy == NULL) + f->fx_done = 1; +} + +valueT +md_section_align (segT segment, valueT size) +{ + int align = bfd_get_section_alignment (stdoutput, segment); + return ((size + (1 << align) - 1) & (-1 << align)); +} + +void +md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, + segT segment ATTRIBUTE_UNUSED, + fragS * fragP ATTRIBUTE_UNUSED) +{ + /* No relaxation yet */ +} diff --git a/gas/config/tc-rl78.h b/gas/config/tc-rl78.h new file mode 100644 index 0000000..c4a16e9 --- /dev/null +++ b/gas/config/tc-rl78.h @@ -0,0 +1,75 @@ +/* tc-rl78.h - header file for Renesas RL78 + Copyright 2011 + 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. */ + +#define TC_RL78 + +extern int target_little_endian; + +#define LISTING_HEADER "RL78 GAS LE" +#define LISTING_LHS_WIDTH 8 +#define LISTING_WORD_SIZE 1 + +#define TARGET_ARCH bfd_arch_rl78 + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#define TARGET_FORMAT "elf32-rl78" + +/* We don't need to handle .word strangely. */ +#define WORKING_DOT_WORD + +/* Permit temporary numeric labels. */ +#define LOCAL_LABELS_FB 1 +/* But make sure that the binutils treat them as locals. */ +#define LOCAL_LABEL_PREFIX '.' + +/* Allow classic-style constants. */ +#define NUMBERS_WITH_SUFFIX 1 + +/* .-foo gets turned into PC relative relocs. */ +#define DIFF_EXPR_OK + +#define md_end rl78_md_end +extern void rl78_md_end (void); + +#define TC_FRAG_TYPE struct rl78_bytesT * +#define TC_FRAG_INIT rl78_frag_init +extern void rl78_frag_init (fragS *); + +/* Call md_pcrel_from_section(), not md_pcrel_from(). */ +#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section (FIXP, SEC) +extern long md_pcrel_from_section (struct fix *, segT); + +/* RL78 doesn't have a 32 bit PCREL relocations. */ +#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) 1 + +#define TC_VALIDATE_FIX_SUB(FIX, SEG) \ + rl78_validate_fix_sub (FIX) +extern int rl78_validate_fix_sub (struct fix *); + +#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \ + rl78_cons_fix_new (FRAG, WHERE, NBYTES, EXP) +extern void rl78_cons_fix_new (fragS *, int, int, expressionS *); + +#define tc_fix_adjustable(x) 0 + +#define RELOC_EXPANSION_POSSIBLE 1 +#define MAX_RELOC_EXPANSION 8 diff --git a/gas/configure b/gas/configure index fdf1fbb..6b4d11c 100755 --- a/gas/configure +++ b/gas/configure @@ -12195,6 +12195,13 @@ _ACEOF fi ;; + rl78) + echo ${extra_objects} | grep -s "rl78-parse.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects rl78-parse.o" + fi + ;; + rx) echo ${extra_objects} | grep -s "rx-parse.o" if test $? -ne 0 ; then diff --git a/gas/configure.in b/gas/configure.in index 9a952c7..acdd105 100644 --- a/gas/configure.in +++ b/gas/configure.in @@ -353,6 +353,13 @@ changequote([,])dnl fi ;; + rl78) + echo ${extra_objects} | grep -s "rl78-parse.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects rl78-parse.o" + fi + ;; + rx) echo ${extra_objects} | grep -s "rx-parse.o" if test $? -ne 0 ; then diff --git a/gas/configure.tgt b/gas/configure.tgt index d98610a..7090682 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -65,6 +65,7 @@ case ${cpu} in powerpc*le*) cpu_type=ppc endian=little ;; powerpc*) cpu_type=ppc endian=big ;; rs6000*) cpu_type=ppc ;; + rl78*) cpu_type=rl78 ;; rx) cpu_type=rx ;; s390x*) cpu_type=s390 arch=s390x ;; s390*) cpu_type=s390 arch=s390 ;; diff --git a/gas/doc/Makefile.am b/gas/doc/Makefile.am index f115ae2..34ccae5 100644 --- a/gas/doc/Makefile.am +++ b/gas/doc/Makefile.am @@ -59,6 +59,7 @@ CPU_DOCS = \ c-pdp11.texi \ c-pj.texi \ c-ppc.texi \ + c-rl78.texi \ c-rx.texi \ c-s390.texi \ c-score.texi \ diff --git a/gas/doc/Makefile.in b/gas/doc/Makefile.in index 93a9f62..e9edb0e 100644 --- a/gas/doc/Makefile.in +++ b/gas/doc/Makefile.in @@ -299,6 +299,7 @@ CPU_DOCS = \ c-pdp11.texi \ c-pj.texi \ c-ppc.texi \ + c-rl78.texi \ c-rx.texi \ c-s390.texi \ c-score.texi \ diff --git a/gas/doc/all.texi b/gas/doc/all.texi index 2be9c72..63282f2 100644 --- a/gas/doc/all.texi +++ b/gas/doc/all.texi @@ -60,6 +60,7 @@ @set PDP11 @set PJ @set PPC +@set RL78 @set RX @set S390 @set SCORE diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index a22eb32..7a41f02 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -6945,6 +6945,9 @@ subject, see the hardware manufacturer's manual. @ifset PPC * PPC-Dependent:: PowerPC Dependent Features @end ifset +@ifset RL78 +* RL78-Dependent:: RL78 Dependent Features +@end ifset @ifset RX * RX-Dependent:: RX Dependent Features @end ifset @@ -7142,6 +7145,10 @@ family. @include c-ppc.texi @end ifset +@ifset RL78 +@include c-rl78.texi +@end ifset + @ifset RX @include c-rx.texi @end ifset diff --git a/gas/doc/c-rl78.texi b/gas/doc/c-rl78.texi new file mode 100644 index 0000000..356439a --- /dev/null +++ b/gas/doc/c-rl78.texi @@ -0,0 +1,121 @@ +@c Copyright 2011 +@c Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node RL78-Dependent +@chapter RL78 Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter RL78 Dependent Features +@end ifclear + +@cindex RL78 support +@menu +* RL78-Opts:: RL78 Assembler Command Line Options +* RL78-Modifiers:: Symbolic Operand Modifiers +* RL78-Directives:: Assembler Directives +* RL78-Float:: Floating Point +* RL78-Syntax:: Syntax +@end menu + +@node RL78-Opts +@section RL78 Options +@cindex options, RL78 +@cindex RL78 options + +The Renesas RL78 port of @code{@value{AS}} has no target-specific +options. + +@node RL78-Modifiers +@section Symbolic Operand Modifiers + +@cindex RL78 modifiers +@cindex syntax, RL78 + +The RL78 has three modifiers that adjust the relocations used by the +linker: + +@table @code + +@item %lo16() + +When loading a 20-bit (or wider) address into registers, this modifier +selects the 16 least significant bits. + +@smallexample + movw ax,#%lo16(_sym) +@end smallexample + +@item %hi16() + +When loading a 20-bit (or wider) address into registers, this modifier +selects the 16 most significant bits. + +@smallexample + movw ax,#%hi16(_sym) +@end smallexample + +@item %hi8() + +When loading a 20-bit (or wider) address into registers, this modifier +selects the 8 bits that would go into CS or ES (i.e. bits 23..16). + +@smallexample + mov es, #%hi8(_sym) +@end smallexample + +@end table + +@node RL78-Directives +@section Assembler Directives + +@cindex assembler directives, RL78 +@cindex RL78 assembler directives + +In addition to the common directives, the RL78 adds these: + +@table @code + +@item .double +Output a constant in ``double'' format, which is a 32-bit floating +point value on RL78. + +@item .bss +Select the BSS section. + +@item .3byte +Output a constant value in a three byte format. + +@item .int +@itemx .word +Output a constant value in a four byte format. + +@end table + +@node RL78-Syntax +@section Syntax for the RL78 +@menu +* RL78-Chars:: Special Characters +@end menu + +@node RL78-Chars +@subsection Special Characters + +@cindex line comment character, RL78 +@cindex RL78 line comment character +The presence of a @samp{;} appearing anywhere on a line indicates the +start of a comment that extends to the end of that line. + +If a @samp{#} appears as the first character of a line then the whole +line is treated as a comment, but in this case the line can also be a +logical line number directive (@pxref{Comments}) or a preprocessor +control command (@pxref{Preprocessing}). + +@cindex line separator, RL78 +@cindex statement separator, RL78 +@cindex RL78 line separator +The @samp{|} character can be used to separate statements on the same +line. |