Browse Source
* configure.ac (rl78-*-*) New case. * configure: Regenerate. [bfd] * Makefile.am (ALL_MACHINES): Add cpu-rl78.lo. (ALL_MACHINES_CFILES): Add cpu-rl78.c. (BFD32_BACKENDS): Add elf32-rl78.lo. (BFD32_BACKENDS_CFILES): Add elf32-rl78.c. (Makefile.in): Regenerate. * archures.c (bfd_architecture): Define bfd_arch_rl78. (bfd_archures_list): Add bfd_rl78_arch. * config.bfd: Add rl78-*-elf. * configure.in: Add bfd_elf32_rl78_vec. * reloc.c (bfd_reloc_code_type): Add BFD_RELOC_RL78_* relocations. * targets.c (bfd_target_vector): Add bfd_elf32_rl78_vec. * Makefile.in: Regenerate. * bfd-in2.h: Regenerate. * configure: Regenerate. * libbfd.h: Regenerate. * cpu-rl78.c: New file. * elf32-rl78.c: New file. [binutils] * readelf.c: Include elf/rl78.h (guess_is_rela): Handle EM_RL78. (dump_relocations): Likewise. (get_machine_name): Likewise. (is_32bit_abs_reloc): Likewise. * NEWS: Mention addition of RL78 support. * MAINTAINERS: Add myself as RL78 port maintainer. [gas] * 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. [include] * dis-asm.h (print_insn_rl78): Declare. [include/elf] * common.h (EM_RL78, EM_78K0R): New. * rl78.h: New. [include/opcode] * rl78.h: New file. [ld] * Makefile.am (ALL_EMULATION_SOURCES): Add eelf32rl78.c. (+eelf32rl78.c): New rule. * Makefile.in: Regenerate. * configure.tgt: Add rl78-*-* case. * emulparams/elf32rl78.sh: New file. * NEWS: Mention addition of Renesas RL78 support. [opcodes] * Makefile.am (TARGET_LIBOPCODES_CFILES): Add rl78-decode.c and rl78-dis.c. (MAINTAINERCLEANFILES): Add rl78-decode.c. (rl78-decode.c): New rule, built from rl78-decode.opc and opc2c. * Makefile.in: Regenerate. * configure.in: Add bfd_rl78_arch case. * configure: Regenerate. * disassemble.c: Define ARCH_rl78. (disassembler): Add ARCH_rl78 case. * rl78-decode.c: New file. * rl78-decode.opc: New file. * rl78-dis.c: New file.gdb_7_4-branch
58 changed files with 12077 additions and 0 deletions
@ -0,0 +1,39 @@ |
|||
/* BFD support for the RL78 processor.
|
|||
Copyright (C) 2011 Free Software Foundation, Inc. |
|||
|
|||
This file is part of BFD, the Binary File Descriptor library. |
|||
|
|||
This program 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 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program 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 this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|||
MA 02110-1301, USA. */ |
|||
|
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
#include "libbfd.h" |
|||
|
|||
const bfd_arch_info_type bfd_rl78_arch = |
|||
{ |
|||
32, /* Bits per word. */ |
|||
32, /* Bits per address. */ |
|||
8, /* Bits per byte. */ |
|||
bfd_arch_rl78, /* Architecture. */ |
|||
bfd_mach_rl78, /* Machine. */ |
|||
"rl78", /* Architecture name. */ |
|||
"rl78", /* Printable name. */ |
|||
4, /* Section align power. */ |
|||
TRUE, /* The default ? */ |
|||
bfd_default_compatible, /* Architecture comparison fn. */ |
|||
bfd_default_scan, /* String to architecture convert fn. */ |
|||
NULL /* Next in list. */ |
|||
}; |
|||
File diff suppressed because it is too large
@ -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 |
|||
File diff suppressed because it is too large
@ -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 */ |
|||
} |
|||
@ -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 |
|||
@ -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. |
|||
@ -0,0 +1,118 @@ |
|||
/* RL78 ELF support for BFD.
|
|||
Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. |
|||
|
|||
This file is part of BFD, the Binary File Descriptor library. |
|||
|
|||
This program 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 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program 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 this program; if not, write to the Free Software Foundation, |
|||
Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
|||
|
|||
#ifndef _ELF_RL78_H |
|||
#define _ELF_RL78_H |
|||
|
|||
#include "elf/reloc-macros.h" |
|||
|
|||
/* Note that there are a few internal relocation types used by the
|
|||
linker to do link-time relaxation. If you update this file, please |
|||
check elf32-rl78.c to see if any of the internal relocations need to |
|||
be, er, relocated. */ |
|||
|
|||
/* Preliminary relocations. */ |
|||
START_RELOC_NUMBERS (elf_rl78_reloc_type) |
|||
|
|||
RELOC_NUMBER (R_RL78_NONE, 0x00) |
|||
/* These are for data, and are bi-endian. */ |
|||
RELOC_NUMBER (R_RL78_DIR32, 0x01) /* Was: R_RL78_32. */ |
|||
RELOC_NUMBER (R_RL78_DIR24S, 0x02) /* Was: R_RL78_24. */ |
|||
RELOC_NUMBER (R_RL78_DIR16, 0x03) |
|||
RELOC_NUMBER (R_RL78_DIR16U, 0x04) /* Was: R_RL78_16_UNS. */ |
|||
RELOC_NUMBER (R_RL78_DIR16S, 0x05) /* Was: R_RL78_16. */ |
|||
RELOC_NUMBER (R_RL78_DIR8, 0x06) |
|||
RELOC_NUMBER (R_RL78_DIR8U, 0x07) /* Was: R_RL78_8_UNS. */ |
|||
RELOC_NUMBER (R_RL78_DIR8S, 0x08) /* Was: R_RL78_8. */ |
|||
|
|||
/* Signed pc-relative values. */ |
|||
RELOC_NUMBER (R_RL78_DIR24S_PCREL, 0x09) /* Was: R_RL78_24_PCREL. */ |
|||
RELOC_NUMBER (R_RL78_DIR16S_PCREL, 0x0a) /* Was: R_RL78_16_PCREL. */ |
|||
RELOC_NUMBER (R_RL78_DIR8S_PCREL, 0x0b) /* Was: R_RL78_8_PCREL. */ |
|||
|
|||
/* These are for fields in the instructions. */ |
|||
RELOC_NUMBER (R_RL78_DIR16UL, 0x0c) |
|||
RELOC_NUMBER (R_RL78_DIR16UW, 0x0d) |
|||
RELOC_NUMBER (R_RL78_DIR8UL, 0x0e) |
|||
RELOC_NUMBER (R_RL78_DIR8UW, 0x0f) |
|||
RELOC_NUMBER (R_RL78_DIR32_REV, 0x10) |
|||
RELOC_NUMBER (R_RL78_DIR16_REV, 0x11) |
|||
RELOC_NUMBER (R_RL78_DIR3U_PCREL, 0x12) |
|||
|
|||
/* These are for complex relocs. */ |
|||
RELOC_NUMBER (R_RL78_ABS32, 0x41) |
|||
RELOC_NUMBER (R_RL78_ABS24S, 0x42) |
|||
RELOC_NUMBER (R_RL78_ABS16, 0x43) |
|||
RELOC_NUMBER (R_RL78_ABS16U, 0x44) |
|||
RELOC_NUMBER (R_RL78_ABS16S, 0x45) |
|||
RELOC_NUMBER (R_RL78_ABS8, 0x46) |
|||
RELOC_NUMBER (R_RL78_ABS8U, 0x47) |
|||
RELOC_NUMBER (R_RL78_ABS8S, 0x48) |
|||
RELOC_NUMBER (R_RL78_ABS24S_PCREL, 0x49) |
|||
RELOC_NUMBER (R_RL78_ABS16S_PCREL, 0x4a) |
|||
RELOC_NUMBER (R_RL78_ABS8S_PCREL, 0x4b) |
|||
RELOC_NUMBER (R_RL78_ABS16UL, 0x4c) |
|||
RELOC_NUMBER (R_RL78_ABS16UW, 0x4d) |
|||
RELOC_NUMBER (R_RL78_ABS8UL, 0x4e) |
|||
RELOC_NUMBER (R_RL78_ABS8UW, 0x4f) |
|||
RELOC_NUMBER (R_RL78_ABS32_REV, 0x50) |
|||
RELOC_NUMBER (R_RL78_ABS16_REV, 0x51) |
|||
|
|||
RELOC_NUMBER (R_RL78_SYM, 0x80) |
|||
RELOC_NUMBER (R_RL78_OPneg, 0x81) |
|||
RELOC_NUMBER (R_RL78_OPadd, 0x82) |
|||
RELOC_NUMBER (R_RL78_OPsub, 0x83) |
|||
RELOC_NUMBER (R_RL78_OPmul, 0x84) |
|||
RELOC_NUMBER (R_RL78_OPdiv, 0x85) |
|||
RELOC_NUMBER (R_RL78_OPshla, 0x86) |
|||
RELOC_NUMBER (R_RL78_OPshra, 0x87) |
|||
RELOC_NUMBER (R_RL78_OPsctsize, 0x88) |
|||
RELOC_NUMBER (R_RL78_OPscttop, 0x8d) |
|||
RELOC_NUMBER (R_RL78_OPand, 0x90) |
|||
RELOC_NUMBER (R_RL78_OPor, 0x91) |
|||
RELOC_NUMBER (R_RL78_OPxor, 0x92) |
|||
RELOC_NUMBER (R_RL78_OPnot, 0x93) |
|||
RELOC_NUMBER (R_RL78_OPmod, 0x94) |
|||
RELOC_NUMBER (R_RL78_OPromtop, 0x95) |
|||
RELOC_NUMBER (R_RL78_OPramtop, 0x96) |
|||
|
|||
END_RELOC_NUMBERS (R_RL78_max) |
|||
|
|||
#define EF_RL78_CPU_RL78 0x00000079 /* FIXME: correct value? */ |
|||
#define EF_RL78_CPU_MASK 0x0000007F /* specific cpu bits. */ |
|||
#define EF_RL78_ALL_FLAGS (EF_RL78_CPU_MASK) |
|||
|
|||
/* Values for the e_flags field in the ELF header. */ |
|||
#define E_FLAG_RL78_64BIT_DOUBLES (1 << 0) |
|||
#define E_FLAG_RL78_DSP (1 << 1) /* Defined in the RL78 CPU Object file specification, but not explained. */ |
|||
|
|||
/* These define the addend field of R_RL78_RH_RELAX relocations. */ |
|||
#define RL78_RELAXA_IMM6 0x00000010 /* Imm8/16/24/32 at bit offset 6. */ |
|||
#define RL78_RELAXA_IMM12 0x00000020 /* Imm8/16/24/32 at bit offset 12. */ |
|||
#define RL78_RELAXA_DSP4 0x00000040 /* Dsp0/8/16 at bit offset 4. */ |
|||
#define RL78_RELAXA_DSP6 0x00000080 /* Dsp0/8/16 at bit offset 6. */ |
|||
#define RL78_RELAXA_DSP14 0x00000100 /* Dsp0/8/16 at bit offset 14. */ |
|||
#define RL78_RELAXA_BRA 0x00000200 /* Any type of branch (must be decoded). */ |
|||
#define RL78_RELAXA_RNUM 0x0000000f /* Number of associated relocations. */ |
|||
/* These mark the place where alignment is requested, and the place where the filler bytes end. */ |
|||
#define RL78_RELAXA_ALIGN 0x10000000 /* Start alignment; the remaining bits are the alignment value. */ |
|||
#define RL78_RELAXA_ELIGN 0x20000000 /* End alignment; the remaining bits are the alignment value. */ |
|||
#define RL78_RELAXA_ANUM 0x00ffffff /* Alignment amount, in bytes (i.e. .balign). */ |
|||
|
|||
#endif /* _ELF_RL78_H */ |
|||
@ -0,0 +1,168 @@ |
|||
/* Opcode decoder for the Renesas RL78
|
|||
Copyright 2011 |
|||
Free Software Foundation, Inc. |
|||
Written by DJ Delorie <dj@redhat.com> |
|||
|
|||
This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler. |
|||
|
|||
This program 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 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program 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 this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA |
|||
02110-1301, USA. */ |
|||
|
|||
/* The RL78 decoder in libopcodes is used by the simulator, gdb's
|
|||
analyzer, and the disassembler. Given an opcode data source, it |
|||
decodes the next opcode into the following structures. */ |
|||
|
|||
#ifndef RL78_OPCODES_H_INCLUDED |
|||
#define RL78_OPCODES_H_INCLUDED |
|||
|
|||
/* For the purposes of these structures, the RL78 registers are as
|
|||
follows, despite most of these being memory-mapped and |
|||
bank-switched: */ |
|||
typedef enum { |
|||
RL78_Reg_None, |
|||
/* The order of these matches the encodings. */ |
|||
RL78_Reg_X, |
|||
RL78_Reg_A, |
|||
RL78_Reg_C, |
|||
RL78_Reg_B, |
|||
RL78_Reg_E, |
|||
RL78_Reg_D, |
|||
RL78_Reg_L, |
|||
RL78_Reg_H, |
|||
/* The order of these matches the encodings. */ |
|||
RL78_Reg_AX, |
|||
RL78_Reg_BC, |
|||
RL78_Reg_DE, |
|||
RL78_Reg_HL, |
|||
/* Unordered. */ |
|||
RL78_Reg_SP, |
|||
RL78_Reg_PSW, |
|||
RL78_Reg_CS, |
|||
RL78_Reg_ES, |
|||
RL78_Reg_PMC, |
|||
RL78_Reg_MEM |
|||
} RL78_Register; |
|||
|
|||
typedef enum |
|||
{ |
|||
RL78_Byte = 0, |
|||
RL78_Word |
|||
} RL78_Size; |
|||
|
|||
typedef enum { |
|||
RL78_Condition_T, |
|||
RL78_Condition_F, |
|||
RL78_Condition_C, |
|||
RL78_Condition_NC, |
|||
RL78_Condition_H, |
|||
RL78_Condition_NH, |
|||
RL78_Condition_Z, |
|||
RL78_Condition_NZ |
|||
} RL78_Condition; |
|||
|
|||
typedef enum { |
|||
RL78_Operand_None = 0, |
|||
RL78_Operand_Immediate, /* #addend */ |
|||
RL78_Operand_Register, /* reg */ |
|||
RL78_Operand_Indirect, /* [reg + reg2 + addend] */ |
|||
RL78_Operand_Bit, /* reg.bit */ |
|||
RL78_Operand_BitIndirect, /* [reg+reg2+addend].bit */ |
|||
RL78_Operand_PreDec, /* [--reg] = push */ |
|||
RL78_Operand_PostInc /* [reg++] = pop */ |
|||
} RL78_Operand_Type; |
|||
|
|||
typedef enum |
|||
{ |
|||
RLO_unknown, |
|||
RLO_add, /* d += s */ |
|||
RLO_addc, /* d += s + CY */ |
|||
RLO_and, /* d &= s (byte, word, bit) */ |
|||
RLO_branch, /* pc = d */ |
|||
RLO_branch_cond, /* pc = d if cond(src) */ |
|||
RLO_branch_cond_clear, /* pc = d if cond(src), and clear(src) */ |
|||
RLO_break, /* BRK */ |
|||
RLO_call, /* call */ |
|||
RLO_cmp, /* cmp d, s */ |
|||
RLO_divhu, /* DIVHU */ |
|||
RLO_divwu, /* DIVWU */ |
|||
RLO_halt, /* HALT */ |
|||
RLO_mov, /* d = s */ |
|||
RLO_mach, /* MACH */ |
|||
RLO_machu, /* MACHU */ |
|||
RLO_mulu, /* MULU */ |
|||
RLO_mulh, /* MULH */ |
|||
RLO_mulhu, /* MULHU */ |
|||
RLO_nop, /* NOP */ |
|||
RLO_or, /* d |= s */ |
|||
RLO_ret, /* RET */ |
|||
RLO_reti, /* RETI */ |
|||
RLO_rol, /* d <<= s, MSB to LSB and CY */ |
|||
RLO_rolc, /* d <<= s, MSB to CY, CY, to LSB */ |
|||
RLO_ror, /* d >>= s, LSB to MSB and CY */ |
|||
RLO_rorc, /* d >>= s, LSB to CY, CY, to MSB */ |
|||
RLO_sar, /* d >>= s, signed */ |
|||
RLO_sel, /* rb = s */ |
|||
RLO_shr, /* d >>= s, unsigned */ |
|||
RLO_shl, /* d <<= s */ |
|||
RLO_skip, /* skip next insn is cond(s) */ |
|||
RLO_stop, /* STOP */ |
|||
RLO_sub, /* d -= s */ |
|||
RLO_subc, /* d -= s - CY */ |
|||
RLO_xch, /* swap d, s */ |
|||
RLO_xor, /* d ^= s */ |
|||
} RL78_Opcode_ID; |
|||
|
|||
typedef struct { |
|||
RL78_Operand_Type type; |
|||
int addend; |
|||
RL78_Register reg : 8; |
|||
RL78_Register reg2 : 8; |
|||
unsigned char bit_number : 4; |
|||
unsigned char condition : 3; |
|||
unsigned char use_es : 1; |
|||
} RL78_Opcode_Operand; |
|||
|
|||
/* PSW flag bits */ |
|||
#define RL78_PSW_IE 0x80 |
|||
#define RL78_PSW_Z 0x40 |
|||
#define RL78_PSW_RBS1 0x20 |
|||
#define RL78_PSW_AC 0x10 |
|||
#define RL78_PSW_RBS0 0x08 |
|||
#define RL78_PSW_ISP1 0x04 |
|||
#define RL78_PSW_ISP0 0x02 |
|||
#define RL78_PSW_CY 0x01 |
|||
|
|||
#define RL78_SFR_SP 0xffff8 |
|||
#define RL78_SFR_PSW 0xffffa |
|||
#define RL78_SFR_CS 0xffffc |
|||
#define RL78_SFR_ES 0xffffd |
|||
#define RL78_SFR_PMC 0xffffe |
|||
#define RL78_SFR_MEM 0xfffff |
|||
|
|||
typedef struct |
|||
{ |
|||
int lineno; |
|||
RL78_Opcode_ID id:24; |
|||
unsigned flags:8; /* PSW mask, for side effects only */ |
|||
int n_bytes; |
|||
char * syntax; |
|||
RL78_Size size; |
|||
/* By convention, these are destination, source. */ |
|||
RL78_Opcode_Operand op[2]; |
|||
} RL78_Opcode_Decoded; |
|||
|
|||
int rl78_decode_opcode (unsigned long, RL78_Opcode_Decoded *, int (*)(void *), void *); |
|||
|
|||
#endif |
|||
@ -0,0 +1,26 @@ |
|||
MACHINE= |
|||
SCRIPT_NAME=elf |
|||
OUTPUT_FORMAT="elf32-rl78" |
|||
# See also `include/elf/rl78.h' |
|||
TEXT_START_ADDR=0x00000 |
|||
ARCH=rl78 |
|||
ENTRY=_start |
|||
EMBEDDED=yes |
|||
TEMPLATE_NAME=elf32 |
|||
ELFSIZE=32 |
|||
EXTRA_EM_FILE=needrelax |
|||
MAXPAGESIZE=256 |
|||
# This is like setting STACK_ADDR to 0xffedc, except that the setting can |
|||
# be overridden, e.g. --defsym _stack=0x0f00, and that we put an extra |
|||
# sentinal value at the bottom. |
|||
# N.B. We can't use PROVIDE to set the default value in a symbol because |
|||
# the address is needed to place the .stack section, which in turn is needed |
|||
# to hold the sentinel value(s). |
|||
test -z "$CREATE_SHLIB" && OTHER_SECTIONS=" .stack ${RELOCATING-0}${RELOCATING+(DEFINED(__stack) ? __stack : 0xffedc)} : |
|||
{ |
|||
${RELOCATING+__stack = .;} |
|||
*(.stack) |
|||
LONG(0xdead) |
|||
}" |
|||
# We do not need .stack for shared library. |
|||
test -n "$CREATE_SHLIB" && OTHER_SECTIONS="" |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,327 @@ |
|||
/* Disassembler code for Renesas RL78.
|
|||
Copyright 2011 Free Software Foundation, Inc. |
|||
Contributed by Red Hat. |
|||
Written by DJ Delorie. |
|||
|
|||
This file is part of the GNU opcodes library. |
|||
|
|||
This library 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. |
|||
|
|||
It 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 this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
|||
MA 02110-1301, USA. */ |
|||
|
|||
#include <stdio.h> |
|||
|
|||
#include "bfd.h" |
|||
#include "dis-asm.h" |
|||
#include "opcode/rl78.h" |
|||
|
|||
#define DEBUG_SEMANTICS 0 |
|||
|
|||
typedef struct |
|||
{ |
|||
bfd_vma pc; |
|||
disassemble_info * dis; |
|||
} RL78_Data; |
|||
|
|||
static int |
|||
rl78_get_byte (void * vdata) |
|||
{ |
|||
bfd_byte buf[1]; |
|||
RL78_Data *rl78_data = (RL78_Data *) vdata; |
|||
|
|||
rl78_data->dis->read_memory_func (rl78_data->pc, |
|||
buf, |
|||
1, |
|||
rl78_data->dis); |
|||
|
|||
rl78_data->pc ++; |
|||
return buf[0]; |
|||
} |
|||
|
|||
static char const * |
|||
register_names[] = |
|||
{ |
|||
"", |
|||
"x", "a", "c", "b", "e", "d", "l", "h", |
|||
"ax", "bc", "de", "hl", |
|||
"sp", "psw", "cs", "es", "pmc", "mem" |
|||
}; |
|||
|
|||
static char const * |
|||
condition_names[] = |
|||
{ |
|||
"t", "f", "c", "nc", "h", "nh", "z", "nz" |
|||
}; |
|||
|
|||
static int |
|||
indirect_type (int t) |
|||
{ |
|||
switch (t) |
|||
{ |
|||
case RL78_Operand_Indirect: |
|||
case RL78_Operand_BitIndirect: |
|||
case RL78_Operand_PostInc: |
|||
case RL78_Operand_PreDec: |
|||
return 1; |
|||
default: |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
int |
|||
print_insn_rl78 (bfd_vma addr, disassemble_info * dis) |
|||
{ |
|||
int rv; |
|||
RL78_Data rl78_data; |
|||
RL78_Opcode_Decoded opcode; |
|||
const char * s; |
|||
#if DEBUG_SEMANTICS |
|||
static char buf[200]; |
|||
#endif |
|||
|
|||
rl78_data.pc = addr; |
|||
rl78_data.dis = dis; |
|||
|
|||
rv = rl78_decode_opcode (addr, &opcode, rl78_get_byte, &rl78_data); |
|||
|
|||
dis->bytes_per_line = 10; |
|||
|
|||
#define PR (dis->fprintf_func) |
|||
#define PS (dis->stream) |
|||
#define PC(c) PR (PS, "%c", c) |
|||
|
|||
s = opcode.syntax; |
|||
|
|||
#if DEBUG_SEMANTICS |
|||
|
|||
switch (opcode.id) |
|||
{ |
|||
case RLO_unknown: s = "uknown"; break; |
|||
case RLO_add: s = "add: %e0%0 += %e1%1"; break; |
|||
case RLO_addc: s = "addc: %e0%0 += %e1%1 + CY"; break; |
|||
case RLO_and: s = "and: %e0%0 &= %e1%1"; break; |
|||
case RLO_branch: s = "branch: pc = %e0%0"; break; |
|||
case RLO_branch_cond: s = "branch_cond: pc = %e0%0 if %c1 / %e1%1"; break; |
|||
case RLO_branch_cond_clear: s = "branch_cond_clear: pc = %e0%0 if %c1 / %e1%1, %e1%1 = 0"; break; |
|||
case RLO_call: s = "call: pc = %e1%0"; break; |
|||
case RLO_cmp: s = "cmp: %e0%0 - %e1%1"; break; |
|||
case RLO_mov: s = "mov: %e0%0 = %e1%1"; break; |
|||
case RLO_or: s = "or: %e0%0 |= %e1%1"; break; |
|||
case RLO_rol: s = "rol: %e0%0 <<= %e1%1"; break; |
|||
case RLO_rolc: s = "rol: %e0%0 <<= %e1%1,CY"; break; |
|||
case RLO_ror: s = "ror: %e0%0 >>= %e1%1"; break; |
|||
case RLO_rorc: s = "ror: %e0%0 >>= %e1%1,CY"; break; |
|||
case RLO_sar: s = "sar: %e0%0 >>= %e1%1 signed"; break; |
|||
case RLO_sel: s = "sel: rb = %1"; break; |
|||
case RLO_shr: s = "shr: %e0%0 >>= %e1%1 unsigned"; break; |
|||
case RLO_shl: s = "shl: %e0%0 <<= %e1%1"; break; |
|||
case RLO_skip: s = "skip: if %c1"; break; |
|||
case RLO_sub: s = "sub: %e0%0 -= %e1%1"; break; |
|||
case RLO_subc: s = "subc: %e0%0 -= %e1%1 - CY"; break; |
|||
case RLO_xch: s = "xch: %e0%0 <-> %e1%1"; break; |
|||
case RLO_xor: s = "xor: %e0%0 ^= %e1%1"; break; |
|||
} |
|||
|
|||
sprintf(buf, "%s%%W%%f\t\033[32m%s\033[0m", s, opcode.syntax); |
|||
s = buf; |
|||
|
|||
#endif |
|||
|
|||
for (; *s; s++) |
|||
{ |
|||
if (*s != '%') |
|||
{ |
|||
PC (*s); |
|||
} |
|||
else |
|||
{ |
|||
RL78_Opcode_Operand * oper; |
|||
int do_hex = 0; |
|||
int do_addr = 0; |
|||
int do_es = 0; |
|||
int do_sfr = 0; |
|||
int do_cond = 0; |
|||
int do_bang = 0; |
|||
|
|||
s ++; |
|||
|
|||
if (*s == 'x') |
|||
{ |
|||
do_hex = 1; |
|||
s++; |
|||
} |
|||
if (*s == '!') |
|||
{ |
|||
do_bang = 1; |
|||
s++; |
|||
} |
|||
if (*s == 'e') |
|||
{ |
|||
do_es = 1; |
|||
s++; |
|||
} |
|||
if (*s == 'a') |
|||
{ |
|||
do_addr = 1; |
|||
s++; |
|||
} |
|||
if (*s == 's') |
|||
{ |
|||
do_sfr = 1; |
|||
s++; |
|||
} |
|||
if (*s == 'c') |
|||
{ |
|||
do_cond = 1; |
|||
s++; |
|||
} |
|||
|
|||
switch (*s) |
|||
{ |
|||
case '%': |
|||
PC ('%'); |
|||
break; |
|||
|
|||
#if DEBUG_SEMANTICS |
|||
|
|||
case 'W': |
|||
if (opcode.size == RL78_Word) |
|||
PR (PS, " \033[33mW\033[0m"); |
|||
break; |
|||
|
|||
case 'f': |
|||
if (opcode.flags) |
|||
{ |
|||
char *comma = ""; |
|||
PR (PS, " \033[35m"); |
|||
|
|||
if (opcode.flags & RL78_PSW_Z) |
|||
{ PR (PS, "Z"); comma = ","; } |
|||
if (opcode.flags & RL78_PSW_AC) |
|||
{ PR (PS, "%sAC", comma); comma = ","; } |
|||
if (opcode.flags & RL78_PSW_CY) |
|||
{ PR (PS, "%sCY", comma); comma = ","; } |
|||
PR (PS, "\033[0m"); |
|||
} |
|||
break; |
|||
|
|||
#endif |
|||
|
|||
case '0': |
|||
case '1': |
|||
oper = opcode.op + *s - '0'; |
|||
if (do_bang) |
|||
PC ('!'); |
|||
|
|||
if (do_es) |
|||
{ |
|||
if (oper->use_es && indirect_type (oper->type)) |
|||
PR (PS, "es:"); |
|||
} |
|||
|
|||
else if (do_cond) |
|||
{ |
|||
PR (PS, "%s", condition_names[oper->condition]); |
|||
} |
|||
|
|||
else |
|||
switch (oper->type) |
|||
{ |
|||
case RL78_Operand_Immediate: |
|||
if (do_addr) |
|||
dis->print_address_func (oper->addend, dis); |
|||
else if (do_hex |
|||
|| oper->addend > 999 |
|||
|| oper->addend < -999) |
|||
PR (PS, "%#x", oper->addend); |
|||
else |
|||
PR (PS, "%d", oper->addend); |
|||
break; |
|||
|
|||
case RL78_Operand_Register: |
|||
PR (PS, "%s", register_names[oper->reg]); |
|||
break; |
|||
|
|||
case RL78_Operand_Bit: |
|||
PR (PS, "%s.%d", register_names[oper->reg], oper->bit_number); |
|||
break; |
|||
|
|||
case RL78_Operand_Indirect: |
|||
case RL78_Operand_BitIndirect: |
|||
switch (oper->reg) |
|||
{ |
|||
case RL78_Reg_None: |
|||
if (oper->addend == 0xffffa && do_sfr && opcode.size == RL78_Byte) |
|||
PR (PS, "psw"); |
|||
else if (oper->addend == 0xffff8 && do_sfr && opcode.size == RL78_Word) |
|||
PR (PS, "sp"); |
|||
else if (oper->addend >= 0xffe20) |
|||
PR (PS, "%#x", oper->addend); |
|||
else |
|||
dis->print_address_func (oper->addend, dis); |
|||
break; |
|||
|
|||
case RL78_Reg_B: |
|||
case RL78_Reg_C: |
|||
case RL78_Reg_BC: |
|||
PR (PS, "%d[%s]", oper->addend, register_names[oper->reg]); |
|||
break; |
|||
|
|||
default: |
|||
PR (PS, "[%s", register_names[oper->reg]); |
|||
if (oper->reg2 != RL78_Reg_None) |
|||
PR (PS, "+%s", register_names[oper->reg2]); |
|||
if (oper->addend) |
|||
PR (PS, "+%d", oper->addend); |
|||
PC (']'); |
|||
break; |
|||
|
|||
} |
|||
if (oper->type == RL78_Operand_BitIndirect) |
|||
PR (PS, ".%d", oper->bit_number); |
|||
break; |
|||
|
|||
#if DEBUG_SEMANTICS |
|||
/* Shouldn't happen - push and pop don't print
|
|||
[SP] directly. But we *do* use them for |
|||
semantic debugging. */ |
|||
case RL78_Operand_PostInc: |
|||
PR (PS, "[%s++]", register_names[oper->reg]); |
|||
break; |
|||
case RL78_Operand_PreDec: |
|||
PR (PS, "[--%s]", register_names[oper->reg]); |
|||
break; |
|||
#endif |
|||
|
|||
default: |
|||
/* If we ever print this, that means the
|
|||
programmer tried to print an operand with a |
|||
type we don't expect. Print the line and |
|||
operand number from rl78-decode.opc for |
|||
them. */ |
|||
PR (PS, "???%d.%d", opcode.lineno, *s - '0'); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
#if DEBUG_SEMANTICS |
|||
|
|||
PR (PS, "\t\033[34m(line %d)\033[0m", opcode.lineno); |
|||
|
|||
#endif |
|||
|
|||
return rv; |
|||
} |
|||
Loading…
Reference in new issue