aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJoern Rennecke <joern.rennecke@embecosm.com>2000-02-17 00:33:36 +0000
committerJoern Rennecke <joern.rennecke@embecosm.com>2000-02-17 00:33:36 +0000
commitd4845d576224bfc03ac8addd72b2991e8eb2fec7 (patch)
tree2916eab1dadb8323316099a339eb6dc0aac522e4 /gas
parentd45b9300fcffb9c44ff73ccda5dac0689c8c4a35 (diff)
downloadgdb-d4845d576224bfc03ac8addd72b2991e8eb2fec7.zip
gdb-d4845d576224bfc03ac8addd72b2991e8eb2fec7.tar.gz
gdb-d4845d576224bfc03ac8addd72b2991e8eb2fec7.tar.bz2
bfd:
Reinstate bits of sh4 support that got accidentally deleted. Add sh-dsp support. bfd: * archures.c (bfd_mach_sh2, bfd_mach_sh_dsp): New macros. (bfd_mach_sh3_dsp): Likewise. (bfd_mach_sh4): Reinstate. (bfd_default_scan): Recognize 7410, 7708, 7729 and 7750. * bfd-in2.h: Regenerate. * coff-sh.c (struct sh_opcode): flags is no longer short. (USESAS, USESAS_REG, USESR8, SETSAS, SETSAS_REG): New macros. (sh_opcode41, sh_opcode42): Integrate as sh_opcode41. (sh_opcode01, sh_opcode02, sh_opcode40): Add sh-dsp opcodes. (sh_opcode41, sh_opcode4, sh_opcode80): Likewise. (sh_opcodes): No longer const. (sh_dsp_opcodef0, sh_dsp_opcodef): New arrays. (sh_insn_uses_reg): Check for USESAS and USESR8. (sh_insn_sets_reg, sh_insns_conflict): Check for SETSAS. (_bfd_sh_align_load_span): Return early for SH4. Modify sh_opcodes lookup table for sh-dsp / sh3-dsp. Take into account that field b of a parallel processing insn could be mistaken for a separate insn. * cpu-sh.c (arch_info_struct): New array elements for sh2, sh-dsp and sh3-dsp. Reinstate element for sh4. (SH2_NEXT, SH_DSP_NEXT, SH3_DSP_NEXT): New macros. (SH4_NEXT): Reinstate. (SH3_NEXT, SH3E_NEXT): Adjust. * elf-bfd.h (_sh_elf_set_mach_from_flags): Declare. * elf32-sh.c (sh_elf_set_private_flags): New function. (sh_elf_copy_private_data, sh_elf_set_mach_from_flags): Likewise. (sh_elf_merge_private_data): New function. (elf_backend_object_p, bfd_elf32_bfd_set_private_bfd_flags): Define. (bfd_elf32_bfd_copy_private_bfd_data): Define. (bfd_elf32_bfd_merge_private_bfd_data): Change to sh_elf_merge_private_data. gas: * config/tc-sh.c ("elf/sh.h"): Include. (sh_dsp, valid_arch, reg_x, reg_y, reg_efg): New static variables. (md.begin): Initialize target_arch. Only include opcodes in has table that match selected architecture. (parse_reg): Recognize register names for sh-dsp. (parse_at): Recognize post-modify addressing. (get_operands): The leading space is now optional. (get_specific): Remove FDREG_N support. Add support for sh-dsp arguments. Update valid_arch. (build_Mytes): Add support for SDT_REG_N. (find_cooked_opcode): New function, broken out of md_assemble. (assemble_ppi, sh_elf_final_processing): New functions. (md_assemble): Use find_cooked_opcode and assemble_ppi. (md_longopts, md_parse_option): New option: -dsp. * config/tc-sh.h (elf_tc_final_processing): Define. (sh_elf_final_processing): Declare. include/elf: * sh.h: (EF_SH_MACH_MASK, EF_SH_UNKNOWN, EF_SH1, EF_SH2): New macros. (EF_SH3, EF_SH_HAS_DSP, EF_SH_DSP, EF_SH3_DSP): Likewise. (EF_SH_HAS_FP, EF_SH3E, EF_SH4, EF_SH_MERGE_MACH): Likewise. opcodes: * sh-dis.c (print_movxy, print_insn_ddt, print_dsp_reg): New functions. (print_insn_ppi): Likewise. (print_insn_shx): Use info->mach to select appropriate insn set. Add support for sh-dsp. Remove FD_REG_N support. * sh-opc.h (sh_nibble_type): Add new values for sh-dsp support. (sh_arg_type): Likewise. Remove FD_REG_N. (sh_dsp_reg_nums): New enum. (arch_sh1, arch_sh2, arch_sh3, arch_sh3e, arch_sh4): New macros. (arch_sh_dsp, arch_sh3_dsp, arch_sh1_up, arch_sh2_up): Likewise. (arch_sh3_up, arch_sh3e_up, arch_sh4_up, arch_sh_dsp_up): Likewise. (arch_sh3_dsp_up): Likewise. (sh_opcode_info): New field: arch. (sh_table): Split up insn with FD_REG_N into ones with F_REG_N and D_REG_N. Fill in arch field. Add sh-dsp insns.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog19
-rw-r--r--gas/config/tc-sh.c641
-rw-r--r--gas/config/tc-sh.h3
3 files changed, 625 insertions, 38 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 912e31c..08c005e 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,22 @@
+Thu Feb 17 00:11:08 2000 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * config/tc-sh.c ("elf/sh.h"): Include.
+ (sh_dsp, valid_arch, reg_x, reg_y, reg_efg): New static variables.
+ (md.begin): Initialize target_arch.
+ Only include opcodes in has table that match selected architecture.
+ (parse_reg): Recognize register names for sh-dsp.
+ (parse_at): Recognize post-modify addressing.
+ (get_operands): The leading space is now optional.
+ (get_specific): Remove FDREG_N support. Add support for sh-dsp
+ arguments. Update valid_arch.
+ (build_Mytes): Add support for SDT_REG_N.
+ (find_cooked_opcode): New function, broken out of md_assemble.
+ (assemble_ppi, sh_elf_final_processing): New functions.
+ (md_assemble): Use find_cooked_opcode and assemble_ppi.
+ (md_longopts, md_parse_option): New option: -dsp.
+ * config/tc-sh.h (elf_tc_final_processing): Define.
+ (sh_elf_final_processing): Declare.
+
Fri Feb 11 14:21:51 2000 Jeffrey A Law (law@cygnus.com)
* config/tc-hppa.c (pa_build_unwind_subspace): Use subseg_new to create
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index 9f7a6c1..777d76c 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -30,6 +30,11 @@
#define DEFINE_TABLE
#include "opcodes/sh-opc.h"
#include <ctype.h>
+
+#ifdef OBJ_ELF
+#include "elf/sh.h"
+#endif
+
const char comment_chars[] = "!";
const char line_separator_chars[] = ";";
const char line_comment_chars[] = "!#";
@@ -39,16 +44,11 @@ static void s_uses PARAMS ((int));
static void sh_count_relocs PARAMS ((bfd *, segT, PTR));
static void sh_frob_section PARAMS ((bfd *, segT, PTR));
-/* This table describes all the machine specific pseudo-ops the assembler
- has to support. The fields are:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function
- */
-
void cons ();
void s_align_bytes ();
static void s_uacons PARAMS ((int));
+static sh_opcode_info *find_cooked_opcode PARAMS ((char **));
+static void assemble_ppi PARAMS ((char *, sh_opcode_info *));
int shl = 0;
@@ -60,6 +60,13 @@ little (ignore)
target_big_endian = 0;
}
+/* This table describes all the machine specific pseudo-ops the assembler
+ has to support. The fields are:
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function
+ */
+
const pseudo_typeS md_pseudo_table[] =
{
{"int", cons, 4},
@@ -84,6 +91,14 @@ int sh_relax; /* set if -relax seen */
int sh_small;
+/* Whether -dsp was seen. */
+
+static int sh_dsp;
+
+/* The bit mask of architectures that could
+ accomodate the insns seen so far. */
+static int valid_arch;
+
const char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant */
@@ -189,16 +204,20 @@ md_begin ()
{
sh_opcode_info *opcode;
char *prev_name = "";
+ int target_arch;
if (! shl)
target_big_endian = 1;
+ target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up);
+ valid_arch = target_arch;
+
opcode_hash_control = hash_new ();
/* Insert unique names into hash table */
for (opcode = sh_table; opcode->name; opcode++)
{
- if (strcmp (prev_name, opcode->name))
+ if (opcode->arch & target_arch && strcmp (prev_name, opcode->name))
{
prev_name = opcode->name;
hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
@@ -214,6 +233,8 @@ md_begin ()
static int reg_m;
static int reg_n;
+static int reg_x, reg_y;
+static int reg_efg;
static int reg_b;
static expressionS immediate; /* absolute expression */
@@ -239,6 +260,23 @@ parse_reg (src, mode, reg)
if (src[0] == 'r')
{
+ if (src[1] == '1')
+ {
+ if (src[2] >= '0' && src[2] <= '5'
+ && ! isalnum ((unsigned char) src[3]))
+ {
+ *mode = A_REG_N;
+ *reg = 10 + src[2] - '0';
+ return 3;
+ }
+ }
+ if (src[1] >= '0' && src[1] <= '9'
+ && ! isalnum ((unsigned char) src[2]))
+ {
+ *mode = A_REG_N;
+ *reg = (src[1] - '0');
+ return 2;
+ }
if (src[1] >= '0' && src[1] <= '7' && strncmp(&src[2], "_bank", 5) == 0
&& ! isalnum ((unsigned char) src[7]))
{
@@ -246,27 +284,121 @@ parse_reg (src, mode, reg)
*reg = (src[1] - '0');
return 7;
}
+
+ if (src[1] == 'e' && ! isalnum ((unsigned char) src[2]))
+ {
+ *mode = A_RE;
+ return 2;
+ }
+ if (src[1] == 's' && ! isalnum ((unsigned char) src[2]))
+ {
+ *mode = A_RS;
+ return 2;
+ }
}
- if (src[0] == 'r')
+ if (src[0] == 'a')
{
+ if (src[1] == '0')
+ {
+ if (! isalnum ((unsigned char) src[2]))
+ {
+ *mode = DSP_REG_N;
+ *reg = A_A0_NUM;
+ return 2;
+ }
+ if (src[2] == 'g' && ! isalnum ((unsigned char) src[3]))
+ {
+ *mode = DSP_REG_N;
+ *reg = A_A0G_NUM;
+ return 3;
+ }
+ }
if (src[1] == '1')
{
- if (src[2] >= '0' && src[2] <= '5'
- && ! isalnum ((unsigned char) src[3]))
+ if (! isalnum ((unsigned char) src[2]))
{
- *mode = A_REG_N;
- *reg = 10 + src[2] - '0';
+ *mode = DSP_REG_N;
+ *reg = A_A1_NUM;
+ return 2;
+ }
+ if (src[2] == 'g' && ! isalnum ((unsigned char) src[3]))
+ {
+ *mode = DSP_REG_N;
+ *reg = A_A1G_NUM;
return 3;
}
}
- if (src[1] >= '0' && src[1] <= '9'
- && ! isalnum ((unsigned char) src[2]))
+
+ if (src[1] == 'x' && src[2] >= '0' && src[2] <= '1'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_REG_N;
- *reg = (src[1] - '0');
+ *reg = 4 + (src[1] - '0');
+ return 3;
+ }
+ if (src[1] == 'y' && src[2] >= '0' && src[2] <= '1'
+ && ! isalnum ((unsigned char) src[3]))
+ {
+ *mode = A_REG_N;
+ *reg = 6 + (src[1] - '0');
+ return 3;
+ }
+ if (src[1] == 's' && src[2] >= '0' && src[2] <= '3'
+ && ! isalnum ((unsigned char) src[3]))
+ {
+ int n = src[1] - '0';
+
+ *mode = A_REG_N;
+ *reg = n | ((~n & 2) << 1);
+ return 3;
+ }
+ }
+
+ if (src[0] == 'i' && src[1] && ! isalnum ((unsigned char) src[3]))
+ {
+ if (src[1] == 's')
+ {
+ *mode = A_REG_N;
+ *reg = 8;
return 2;
}
+ if (src[1] == 'x')
+ {
+ *mode = A_REG_N;
+ *reg = 8;
+ return 2;
+ }
+ if (src[1] == 'y')
+ {
+ *mode = A_REG_N;
+ *reg = 9;
+ return 2;
+ }
+ }
+
+ if (src[0] == 'x' && src[1] >= '0' && src[1] <= '1'
+ && ! isalnum ((unsigned char) src[2]))
+ {
+ *mode = DSP_REG_N;
+ *reg = A_X0_NUM + src[1] - '0';
+ return 2;
+ }
+
+ if (src[0] == 'y' && src[1] >= '0' && src[1] <= '1'
+ && ! isalnum ((unsigned char) src[2]))
+ {
+ *mode = DSP_REG_N;
+ *reg = A_Y0_NUM + src[1] - '0';
+ return 2;
+ }
+
+ if (src[0] == 'm' && src[1] >= '0' && src[1] <= '1'
+ && ! isalnum ((unsigned char) src[2]))
+ {
+ *mode = DSP_REG_N;
+ *reg = src[1] == '0' ? A_M0_NUM : A_M1_NUM;
+ return 2;
}
if (src[0] == 's'
@@ -291,6 +423,13 @@ parse_reg (src, mode, reg)
return 3;
}
+ if (src[0] == 'd' && src[1] == 's' && src[2] == 'r'
+ && ! isalnum ((unsigned char) src[3]))
+ {
+ *mode = A_DSR;
+ return 3;
+ }
+
if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r'
&& ! isalnum ((unsigned char) src[3]))
{
@@ -348,6 +487,12 @@ parse_reg (src, mode, reg)
return 4;
}
}
+ if (src[0] == 'm' && src[1] == 'o' && src[2] == 'd'
+ && ! isalnum ((unsigned char) src[4]))
+ {
+ *mode = A_MOD;
+ return 3;
+ }
if (src[0] == 'f' && src[1] == 'r')
{
if (src[2] == '1')
@@ -605,8 +750,21 @@ parse_at (src, op)
}
if (src[0] == '+')
{
- op->type = A_INC_N;
src++;
+ if ((src[0] == 'r' && src[1] == '8')
+ || (src[0] == 'i' && (src[1] == 'x' || src[1] == 's')))
+ {
+ src += 2;
+ op->type = A_PMOD_N;
+ }
+ if ((src[0] == 'r' && src[1] == '9')
+ || (src[0] == 'i' && src[1] == 'y'))
+ {
+ src += 2;
+ op->type = A_PMODY_N;
+ }
+ else
+ op->type = A_INC_N;
}
else
{
@@ -665,7 +823,11 @@ get_operands (info, args, operand)
char *ptr = args;
if (info->arg[0])
{
- ptr++;
+ /* The pre-processor will eliminate whitespace in front of '@'
+ after the first argument; we may be called multiple times
+ from assemble_ppi, so don't insist on finding whitespace here. */
+ if (*ptr == ' ')
+ ptr++;
get_operand (&ptr, operand + 0);
if (info->arg[1])
@@ -774,16 +936,14 @@ get_specific (opcode, operands)
case V_REG_N:
case FPUL_N:
case FPSCR_N:
+ case A_PMOD_N:
+ case A_PMODY_N:
+ case DSP_REG_N:
/* Opcode needs rn */
if (user->type != arg)
goto fail;
reg_n = user->reg;
break;
- case FD_REG_N:
- if (user->type != F_REG_N && user->type != D_REG_N)
- goto fail;
- reg_n = user->reg;
- break;
case DX_REG_N:
if (user->type != D_REG_N && user->type != X_REG_N)
goto fail;
@@ -792,6 +952,10 @@ get_specific (opcode, operands)
case A_GBR:
case A_SR:
case A_VBR:
+ case A_DSR:
+ case A_MOD:
+ case A_RE:
+ case A_RS:
case A_SSR:
case A_SPC:
case A_SGR:
@@ -812,12 +976,144 @@ get_specific (opcode, operands)
case A_IND_M:
case A_IND_R0_REG_M:
case A_DISP_REG_M:
+ case DSP_REG_M:
/* Opcode needs rn */
if (user->type != arg - A_REG_M + A_REG_N)
goto fail;
reg_m = user->reg;
break;
+ case DSP_REG_X:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_X0_NUM:
+ reg_x = 0;
+ break;
+ case A_X1_NUM:
+ reg_x = 1;
+ break;
+ case A_A0_NUM:
+ reg_x = 2;
+ break;
+ case A_A1_NUM:
+ reg_x = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_Y:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_Y0_NUM:
+ reg_y = 0;
+ break;
+ case A_Y1_NUM:
+ reg_y = 1;
+ break;
+ case A_M0_NUM:
+ reg_y = 2;
+ break;
+ case A_M1_NUM:
+ reg_y = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_E:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_X0_NUM:
+ reg_efg = 0 << 10;
+ break;
+ case A_X1_NUM:
+ reg_efg = 1 << 10;
+ break;
+ case A_Y0_NUM:
+ reg_efg = 2 << 10;
+ break;
+ case A_A1_NUM:
+ reg_efg = 3 << 10;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_F:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_Y0_NUM:
+ reg_efg |= 0 << 8;
+ break;
+ case A_Y1_NUM:
+ reg_efg |= 1 << 8;
+ break;
+ case A_X0_NUM:
+ reg_efg |= 2 << 8;
+ break;
+ case A_A1_NUM:
+ reg_efg |= 3 << 8;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_G:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_M0_NUM:
+ reg_efg |= 0 << 2;
+ break;
+ case A_M1_NUM:
+ reg_efg |= 1 << 2;
+ break;
+ case A_A0_NUM:
+ reg_efg |= 2 << 2;
+ break;
+ case A_A1_NUM:
+ reg_efg |= 3 << 2;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case A_A0:
+ if (user->type != DSP_REG_N || user->reg != A_A0_NUM)
+ goto fail;
+ break;
+ case A_X0:
+ if (user->type != DSP_REG_N || user->reg != A_X0_NUM)
+ goto fail;
+ break;
+ case A_X1:
+ if (user->type != DSP_REG_N || user->reg != A_X1_NUM)
+ goto fail;
+ break;
+ case A_Y0:
+ if (user->type != DSP_REG_N || user->reg != A_Y0_NUM)
+ goto fail;
+ break;
+ case A_Y1:
+ if (user->type != DSP_REG_N || user->reg != A_Y1_NUM)
+ goto fail;
+ break;
+
case F_REG_M:
case D_REG_M:
case X_REG_M:
@@ -845,6 +1141,7 @@ get_specific (opcode, operands)
goto fail;
}
}
+ valid_arch &= this_try->arch;
return this_try;
fail:;
}
@@ -949,6 +1246,11 @@ build_Mytes (opcode, operand)
case REG_M:
nbuf[index] = reg_m;
break;
+ case SDT_REG_N:
+ if (reg_n < 2 || reg_n > 5)
+ as_bad (_("Invalid register: 'r%d'"), reg_n);
+ nbuf[index] = (reg_n & 3) | 4;
+ break;
case REG_NM:
nbuf[index] = reg_n | (reg_m >> 2);
break;
@@ -997,50 +1299,274 @@ build_Mytes (opcode, operand)
}
}
-/* This is the guts of the machine-dependent assembler. STR points to a
- machine dependent instruction. This function is supposed to emit
- the frags/bytes it assembles to.
- */
+/* Find an opcode at the start of *STR_P in the hash table, and set
+ *STR_P to the first character after the last one read. */
-void
-md_assemble (str)
- char *str;
+static sh_opcode_info *
+find_cooked_opcode (str_p)
+ char **str_p;
{
+ char *str = *str_p;
unsigned char *op_start;
unsigned char *op_end;
- sh_operand_info operand[3];
- sh_opcode_info *opcode;
char name[20];
int nlen = 0;
/* Drop leading whitespace */
while (*str == ' ')
str++;
- /* find the op code end */
+ /* Find the op code end.
+ The pre-processor will eliminate whitespace in front of
+ any '@' after the first argument; we may be called from
+ assemble_ppi, so the opcode might be terminated by an '@'. */
for (op_start = op_end = (unsigned char *) (str);
*op_end
&& nlen < 20
- && !is_end_of_line[*op_end] && *op_end != ' ';
+ && !is_end_of_line[*op_end] && *op_end != ' ' && *op_end != '@';
op_end++)
{
unsigned char c = op_start[nlen];
/* The machine independent code will convert CMP/EQ into cmp/EQ
- because it thinks the '/' is the end of the symbol. Instead of
- hacking up the machine independent code, we just deal with it
- here. */
+ because it thinks the '/' is the end of the symbol. Moreover,
+ all but the first sub-insn is a parallel processing insn won't
+ be capitailzed. Instead of hacking up the machine independent
+ code, we just deal with it here. */
c = isupper (c) ? tolower (c) : c;
name[nlen] = c;
nlen++;
}
name[nlen] = 0;
+ *str_p = op_end;
if (nlen == 0)
{
as_bad (_("can't find opcode "));
}
- opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name);
+ return (sh_opcode_info *) hash_find (opcode_hash_control, name);
+}
+
+/* Assemble a parallel processing insn. */
+#define DDT_BASE 0xf000 /* Base value for double data transfer insns */
+static void
+assemble_ppi (op_end, opcode)
+ char *op_end;
+ sh_opcode_info *opcode;
+{
+ int movx = 0;
+ int movy = 0;
+ int cond = 0;
+ int field_b = 0;
+ char *output;
+ int move_code;
+
+ /* Some insn ignore one or more register fields, e.g. psts machl,a0.
+ Make sure we encode a defined insn pattern. */
+ reg_x = 0;
+ reg_y = 0;
+
+ for (;;)
+ {
+ sh_operand_info operand[3];
+
+ if (opcode->arg[0] != A_END)
+ op_end = get_operands (opcode, op_end, operand);
+ opcode = get_specific (opcode, operand);
+ if (opcode == 0)
+ {
+ /* Couldn't find an opcode which matched the operands */
+ char *where = frag_more (2);
+
+ where[0] = 0x0;
+ where[1] = 0x0;
+ as_bad (_("invalid operands for opcode"));
+ return;
+ }
+ if (opcode->nibbles[0] != PPI)
+ as_bad (_("insn can't be combined with parallel processing insn"));
+
+ switch (opcode->nibbles[1])
+ {
+
+ case NOPX:
+ if (movx)
+ as_bad (_("multiple movx specifications"));
+ movx = DDT_BASE;
+ break;
+ case NOPY:
+ if (movy)
+ as_bad (_("multiple movy specifications"));
+ movy = DDT_BASE;
+ break;
+
+ case MOVX:
+ if (movx)
+ as_bad (_("multiple movx specifications"));
+ if (reg_n < 4 || reg_n > 5)
+ as_bad (_("invalid movx address register"));
+ if (opcode->nibbles[2] & 8)
+ {
+ if (reg_m == A_A1_NUM)
+ movx = 1 << 7;
+ else if (reg_m != A_A0_NUM)
+ as_bad (_("invalid movx dsp register"));
+ }
+ else
+ {
+ if (reg_x > 1)
+ as_bad (_("invalid movx dsp register"));
+ movx = reg_x << 7;
+ }
+ movx += ((reg_n - 4) << 9) + (opcode->nibbles[2] << 2) + DDT_BASE;
+ break;
+
+ case MOVY:
+ if (movy)
+ as_bad (_("multiple movy specifications"));
+ if (opcode->nibbles[2] & 8)
+ {
+ /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,
+ so add 8 more. */
+ movy = 8;
+ if (reg_m == A_A1_NUM)
+ movy += 1 << 6;
+ else if (reg_m != A_A0_NUM)
+ as_bad (_("invalid movy dsp register"));
+ }
+ else
+ {
+ if (reg_y > 1)
+ as_bad (_("invalid movy dsp register"));
+ movy = reg_y << 6;
+ }
+ if (reg_n < 6 || reg_n > 7)
+ as_bad (_("invalid movy address register"));
+ movy += ((reg_n - 6) << 8) + opcode->nibbles[2] + DDT_BASE;
+ break;
+
+ case PSH:
+ if (immediate.X_op != O_constant)
+ as_bad (_("dsp immediate shift value not constant"));
+ field_b = ((opcode->nibbles[2] << 12)
+ | (immediate.X_add_number & 127) << 4
+ | reg_n);
+ break;
+ case PPI3:
+ if (field_b)
+ as_bad (_("multiple parallel processing specifications"));
+ field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
+ + (reg_x << 6) + (reg_y << 4) + reg_n);
+ break;
+ case PDC:
+ if (cond)
+ as_bad (_("multiple condition specifications"));
+ cond = opcode->nibbles[2] << 8;
+ if (*op_end)
+ goto skip_cond_check;
+ break;
+ case PPIC:
+ if (field_b)
+ as_bad (_("multiple parallel processing specifications"));
+ field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
+ + cond + (reg_x << 6) + (reg_y << 4) + reg_n);
+ cond = 0;
+ break;
+ case PMUL:
+ if (field_b)
+ {
+ if ((field_b & 0xef00) != 0xa100)
+ as_bad (_("insn cannot be combined with pmuls"));
+ field_b -= 0x8100;
+ switch (field_b & 0xf)
+ {
+ case A_X0_NUM:
+ field_b += 0 - A_X0_NUM;
+ break;
+ case A_Y0_NUM:
+ field_b += 1 - A_Y0_NUM;
+ break;
+ case A_A0_NUM:
+ field_b += 2 - A_A0_NUM;
+ break;
+ case A_A1_NUM:
+ field_b += 3 - A_A1_NUM;
+ break;
+ default:
+ as_bad (_("bad padd / psub pmuls output operand"));
+ }
+ }
+ field_b += 0x4000 + reg_efg;
+ break;
+ default:
+ abort ();
+ }
+ if (cond)
+ {
+ as_bad (_("condition not followed by conditionalizable insn"));
+ cond = 0;
+ }
+ if (! *op_end)
+ break;
+ skip_cond_check:
+ opcode = find_cooked_opcode (&op_end);
+ if (opcode == NULL)
+ {
+ (as_bad
+ (_("unrecognized characters at end of parallel processing insn")));
+ break;
+ }
+ }
+
+ move_code = movx | movy;
+ if (field_b)
+ {
+ /* Parallel processing insn. */
+ unsigned long ppi_code = (movx | movy | 0xf800) << 16 | field_b;
+
+ output = frag_more (4);
+ if (! target_big_endian)
+ {
+ output[3] = ppi_code >> 8;
+ output[2] = ppi_code;
+ }
+ else
+ {
+ output[2] = ppi_code >> 8;
+ output[3] = ppi_code;
+ }
+ move_code |= 0xf800;
+ }
+ else
+ /* Just a double data transfer. */
+ output = frag_more (2);
+ if (! target_big_endian)
+ {
+ output[1] = move_code >> 8;
+ output[0] = move_code;
+ }
+ else
+ {
+ output[0] = move_code >> 8;
+ output[1] = move_code;
+ }
+}
+
+/* This is the guts of the machine-dependent assembler. STR points to a
+ machine dependent instruction. This function is supposed to emit
+ the frags/bytes it assembles to.
+ */
+
+void
+md_assemble (str)
+ char *str;
+{
+ unsigned char *op_end;
+ sh_operand_info operand[3];
+ sh_opcode_info *opcode;
+
+ opcode = find_cooked_opcode (&str);
+ op_end = str;
if (opcode == NULL)
{
@@ -1058,6 +1584,12 @@ md_assemble (str)
seg_info (now_seg)->tc_segment_info_data.in_code = 1;
}
+ if (opcode->nibbles[0] == PPI)
+ {
+ assemble_ppi (op_end, opcode);
+ return;
+ }
+
if (opcode->arg[0] == A_BDISP12
|| opcode->arg[0] == A_BDISP8)
{
@@ -1257,10 +1789,12 @@ struct option md_longopts[] = {
#define OPTION_RELAX (OPTION_MD_BASE)
#define OPTION_LITTLE (OPTION_MD_BASE + 1)
#define OPTION_SMALL (OPTION_LITTLE + 1)
+#define OPTION_DSP (OPTION_SMALL + 1)
{"relax", no_argument, NULL, OPTION_RELAX},
{"little", no_argument, NULL, OPTION_LITTLE},
{"small", no_argument, NULL, OPTION_SMALL},
+ {"dsp", no_argument, NULL, OPTION_DSP},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof(md_longopts);
@@ -1285,6 +1819,10 @@ md_parse_option (c, arg)
sh_small = 1;
break;
+ case OPTION_DSP:
+ sh_dsp = 1;
+ break;
+
default:
return 0;
}
@@ -1886,6 +2424,33 @@ sh_fix_adjustable (fixP)
return 1;
}
+
+void sh_elf_final_processing()
+{
+ int val;
+
+ /* Set file-specific flags to indicate if this code needs
+ a processor with the sh-dsp / sh3e ISA to execute. */
+ if (valid_arch & arch_sh1)
+ val = EF_SH1;
+ else if (valid_arch & arch_sh2)
+ val = EF_SH2;
+ else if (valid_arch & arch_sh_dsp)
+ val = EF_SH_DSP;
+ else if (valid_arch & arch_sh3)
+ val = EF_SH3;
+ else if (valid_arch & arch_sh3_dsp)
+ val = EF_SH_DSP;
+ else if (valid_arch & arch_sh3e)
+ val = EF_SH3E;
+ else if (valid_arch & arch_sh4)
+ val = EF_SH4;
+ else
+ abort ();
+
+ elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
+ elf_elfheader (stdoutput)->e_flags |= val;
+}
#endif
/* Apply a fixup to the object file. */
diff --git a/gas/config/tc-sh.h b/gas/config/tc-sh.h
index f4278c2..90129c2 100644
--- a/gas/config/tc-sh.h
+++ b/gas/config/tc-sh.h
@@ -149,6 +149,9 @@ extern int target_big_endian;
#define TARGET_FORMAT (shl ? "elf32-shl" : "elf32-sh")
+#define elf_tc_final_processing sh_elf_final_processing
+extern void sh_elf_final_processing PARAMS ((void));
+
#endif /* OBJ_ELF */
/* end of tc-sh.h */