1600 lines
36 KiB
Text
1600 lines
36 KiB
Text
/* rl78-parse.y Renesas RL78 parser
|
|
Copyright (C) 2011-2022 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;
|
|
static int rl78_bit_insn = 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 SET_SA(e) e.X_md = BFD_RELOC_RL78_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");
|
|
|
|
#define ISA_G10(s) if (!rl78_isa_g10()) rl78_error (s " is only supported on the G10")
|
|
#define ISA_G13(s) if (!rl78_isa_g13()) rl78_error (s " is only supported on the G13")
|
|
#define ISA_G14(s) if (!rl78_isa_g14()) rl78_error (s " is only supported on the G14")
|
|
|
|
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 NOT1
|
|
%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); SET_SA ($2); 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); SET_SA ($4); O1 ($4); }
|
|
|
|
| addsub A ',' opt_es '!' EXPR
|
|
{ B1 (0x0f|$1); O2 ($6); rl78_linkrelax_addr16 (); }
|
|
|
|
| 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); rl78_linkrelax_addr16 (); }
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); SET_SA ($4); O1 ($4); }
|
|
|
|
| addsubw AX ',' opt_es '!' EXPR
|
|
{ B1 (0x02|$1); O2 ($6); rl78_linkrelax_addr16 (); }
|
|
|
|
| addsubw AX ',' opt_es '[' HL '+' EXPR ']'
|
|
{ B2 (0x61, 0x09|$1); O1 ($8); }
|
|
|
|
| addsubw AX ',' opt_es '[' HL ']'
|
|
{ B3 (0x61, 0x09|$1, 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); SET_SA ($4); 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); rl78_linkrelax_branch (); }
|
|
|
|
| BNC '$' EXPR
|
|
{ B1 (0xde); PC1 ($3); rl78_linkrelax_branch (); }
|
|
|
|
| BZ '$' EXPR
|
|
{ B1 (0xdd); PC1 ($3); rl78_linkrelax_branch (); }
|
|
|
|
| BNZ '$' EXPR
|
|
{ B1 (0xdf); PC1 ($3); rl78_linkrelax_branch (); }
|
|
|
|
| BH '$' EXPR
|
|
{ B2 (0x61, 0xc3); PC1 ($3); rl78_linkrelax_branch (); }
|
|
|
|
| BNH '$' EXPR
|
|
{ B2 (0x61, 0xd3); PC1 ($3); rl78_linkrelax_branch (); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); SET_SA ($2); 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); rl78_linkrelax_branch (); }
|
|
|
|
| BR '$' '!' EXPR
|
|
{ B1 (0xee); PC2 ($4); rl78_linkrelax_branch (); }
|
|
|
|
| BR '!' EXPR
|
|
{ B1 (0xed); O2 ($3); rl78_linkrelax_branch (); }
|
|
|
|
| BR '!' '!' EXPR
|
|
{ B1 (0xec); O3 ($4); rl78_linkrelax_branch (); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); rl78_linkrelax_branch (); }
|
|
|
|
| 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); SET_SA ($2); 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); rl78_linkrelax_addr16 (); }
|
|
|
|
| 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); SET_SA ($2); O1 ($2); }
|
|
|
|
| oneclrb opt_es '!' EXPR
|
|
{ B1 (0xe5|$1); O2 ($4); rl78_linkrelax_addr16 (); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); SET_SA ($2); O1 ($2); }
|
|
|
|
| CMP0 opt_es '!' EXPR
|
|
{ B1 (0xd5); O2 ($4); rl78_linkrelax_addr16 (); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); SET_SA ($2); O1 ($2); }
|
|
| incdec '!' EXPR
|
|
{ B1 (0xa0|$1); O2 ($3); rl78_linkrelax_addr16 (); }
|
|
| 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); SET_SA ($2); O1 ($2); }
|
|
|
|
| incdecw opt_es '!' EXPR
|
|
{ B1 (0xa2|$1); O2 ($4); rl78_linkrelax_addr16 (); }
|
|
|
|
| incdecw opt_es '[' HL '+' EXPR ']'
|
|
{ B2 (0x61, 0x79+$1); O1 ($6); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| DI
|
|
{ B3 (0x71, 0x7b, 0xfa); }
|
|
|
|
| EI
|
|
{ B3 (0x71, 0x7a, 0xfa); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| MULHU { ISA_G14 ("MULHU"); }
|
|
{ B3 (0xce, 0xfb, 0x01); }
|
|
|
|
| MULH { ISA_G14 ("MULH"); }
|
|
{ B3 (0xce, 0xfb, 0x02); }
|
|
|
|
| MULU X
|
|
{ B1 (0xd6); }
|
|
|
|
| DIVHU { ISA_G14 ("DIVHU"); }
|
|
{ B3 (0xce, 0xfb, 0x03); }
|
|
|
|
/* Note that the DIVWU encoding was changed from [0xce,0xfb,0x04] to
|
|
[0xce,0xfb,0x0b]. Different versions of the Software Manual exist
|
|
with the same version number, but varying encodings. The version
|
|
here matches the hardware. */
|
|
|
|
| DIVWU { ISA_G14 ("DIVWU"); }
|
|
{ B3 (0xce, 0xfb, 0x0b); }
|
|
|
|
| MACHU { ISA_G14 ("MACHU"); }
|
|
{ B3 (0xce, 0xfb, 0x05); }
|
|
|
|
| MACH { ISA_G14 ("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); SET_SA ($3); O1 ($3); O1 ($6); }
|
|
else
|
|
NOT_SFR_OR_SADDR;
|
|
}
|
|
|
|
| MOV '!' EXPR ',' '#' EXPR
|
|
{ B1 (0xcf); O2 ($3); O1 ($6); rl78_linkrelax_addr16 (); }
|
|
|
|
| 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); SET_SA ($3); O1 ($3); }
|
|
else
|
|
NOT_SFR_OR_SADDR;
|
|
}
|
|
|
|
| MOV A ',' opt_es '!' EXPR
|
|
{ B1 (0x8f); O2 ($6); rl78_linkrelax_addr16 (); }
|
|
|
|
| MOV '!' EXPR ',' A
|
|
{ B1 (0x9f); O2 ($3); rl78_linkrelax_addr16 (); }
|
|
|
|
| MOV ES ':' '!' EXPR ',' A
|
|
{ B2 (0x11, 0x9f); O2 ($5); }
|
|
|
|
| MOV regb_na ',' opt_es '!' EXPR
|
|
{ B1 (0xc9|reg_xbc($2)); O2 ($6); rl78_linkrelax_addr16 (); }
|
|
|
|
| MOV A ',' opt_es EXPR {NOT_ES}
|
|
{ if (expr_is_saddr ($5))
|
|
{ B1 (0x8d); SET_SA ($5); 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)); SET_SA ($5); 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); SET_SA ($5); 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); SET_SA ($4); 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); SET_SA ($2); 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); SET_SA ($3); 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); SET_SA ($5); 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); SET_SA ($3); 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); rl78_linkrelax_addr16 (); }
|
|
|
|
| MOVW opt_es '!' EXPR ',' AX
|
|
{ B1 (0xbf); O2 ($4); WA($4); rl78_linkrelax_addr16 (); }
|
|
|
|
| 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); SET_SA ($4); O1 ($4); WA($4); }
|
|
|
|
| MOVW regw_na ',' opt_es '!' EXPR
|
|
{ B1 (0xcb); F ($2, 2, 2); O2 ($6); WA($6); rl78_linkrelax_addr16 (); }
|
|
|
|
| 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); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| NOT1 CY
|
|
{ B2 (0x71, 0xc0); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); rl78_relax (RL78_RELAX_BRANCH, 0); }
|
|
|
|
| SKH
|
|
{ B2 (0x61, 0xe3); rl78_relax (RL78_RELAX_BRANCH, 0); }
|
|
|
|
| SKNC
|
|
{ B2 (0x61, 0xd8); rl78_relax (RL78_RELAX_BRANCH, 0); }
|
|
|
|
| SKNH
|
|
{ B2 (0x61, 0xf3); rl78_relax (RL78_RELAX_BRANCH, 0); }
|
|
|
|
| SKNZ
|
|
{ B2 (0x61, 0xf8); rl78_relax (RL78_RELAX_BRANCH, 0); }
|
|
|
|
| SKZ
|
|
{ B2 (0x61, 0xe8); rl78_relax (RL78_RELAX_BRANCH, 0); }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
| 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); rl78_linkrelax_addr16 (); }
|
|
|
|
| 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); SET_SA ($4); 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; rl78_bit_insn = 1; }
|
|
| OR1 { $$ = 0x06; rl78_bit_insn = 1; }
|
|
| XOR1 { $$ = 0x07; rl78_bit_insn = 1; }
|
|
;
|
|
|
|
bt_bf : BT { $$ = 0x02; rl78_bit_insn = 1; rl78_linkrelax_branch (); }
|
|
| BF { $$ = 0x04; rl78_bit_insn = 1; rl78_linkrelax_branch (); }
|
|
| BTCLR { $$ = 0x00; rl78_bit_insn = 1; }
|
|
;
|
|
|
|
setclr1 : SET1 { $$ = 0; rl78_bit_insn = 1; }
|
|
| CLR1 { $$ = 1; rl78_bit_insn = 1; }
|
|
;
|
|
|
|
oneclrb : ONEB { $$ = 0x00; }
|
|
| CLRB { $$ = 0x10; }
|
|
;
|
|
|
|
oneclrw : ONEW { $$ = 0x00; }
|
|
| CLRW { $$ = 0x10; }
|
|
;
|
|
|
|
incdec : INC { $$ = 0x00; }
|
|
| DEC { $$ = 0x10; }
|
|
;
|
|
|
|
incdecw : INCW { $$ = 0x00; }
|
|
| DECW { $$ = 0x10; }
|
|
;
|
|
|
|
mov1 : MOV1 { rl78_bit_insn = 1; }
|
|
;
|
|
|
|
%%
|
|
/* ====================================================================== */
|
|
|
|
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(NOT1),
|
|
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;
|
|
|
|
rl78_bit_insn = 0;
|
|
|
|
setbuf (stdout, 0);
|
|
}
|
|
|
|
/* Return a pointer to the '.' in a bit index expression (like
|
|
foo.5), or NULL if none is found. */
|
|
static char *
|
|
find_bit_index (char *tok)
|
|
{
|
|
char *last_dot = NULL;
|
|
char *last_digit = NULL;
|
|
while (*tok && *tok != ',')
|
|
{
|
|
if (*tok == '.')
|
|
{
|
|
last_dot = tok;
|
|
last_digit = NULL;
|
|
}
|
|
else if (*tok >= '0' && *tok <= '7'
|
|
&& last_dot != NULL
|
|
&& last_digit == NULL)
|
|
{
|
|
last_digit = tok;
|
|
}
|
|
else if (ISSPACE (*tok))
|
|
{
|
|
/* skip */
|
|
}
|
|
else
|
|
{
|
|
last_dot = NULL;
|
|
last_digit = NULL;
|
|
}
|
|
tok ++;
|
|
}
|
|
if (last_dot != NULL
|
|
&& last_digit != NULL)
|
|
return last_dot;
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
rl78_lex (void)
|
|
{
|
|
/*unsigned int ci;*/
|
|
char * save_input_pointer;
|
|
char * bit = NULL;
|
|
|
|
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_bit_insn
|
|
&& *rl78_lex_start == '.'
|
|
&& find_bit_index (rl78_lex_start) == rl78_lex_start)
|
|
{
|
|
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 ++;
|
|
}
|
|
|
|
/* Again, '.' is funny. Look for '.<digit>' at the end of the line
|
|
or before a comma, which is a bitfield, not an expression. */
|
|
|
|
if (rl78_bit_insn)
|
|
{
|
|
bit = find_bit_index (rl78_lex_start);
|
|
if (bit)
|
|
*bit = 0;
|
|
else
|
|
bit = NULL;
|
|
}
|
|
|
|
save_input_pointer = input_line_pointer;
|
|
input_line_pointer = rl78_lex_start;
|
|
rl78_lval.exp.X_md = 0;
|
|
expression (&rl78_lval.exp);
|
|
|
|
if (bit)
|
|
*bit = '.';
|
|
|
|
rl78_lex_start = input_line_pointer;
|
|
input_line_pointer = save_input_pointer;
|
|
rl78_last_token = EXPR;
|
|
return EXPR;
|
|
}
|
|
|
|
int
|
|
rl78_error (const 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 1;
|
|
|
|
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;
|
|
}
|