aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorMichael Snyder <msnyder@vmware.com>2003-12-05 01:59:55 +0000
committerMichael Snyder <msnyder@vmware.com>2003-12-05 01:59:55 +0000
commit88da98f3d4f49910317f92e6bbae8e4b43acd685 (patch)
treebc658859f5d12838097ea7dd36268007b1c2684c /gas/config
parentb74b6d0b9f1e7fa82b548ac6122726eb825be96d (diff)
downloadfsf-binutils-gdb-88da98f3d4f49910317f92e6bbae8e4b43acd685.zip
fsf-binutils-gdb-88da98f3d4f49910317f92e6bbae8e4b43acd685.tar.gz
fsf-binutils-gdb-88da98f3d4f49910317f92e6bbae8e4b43acd685.tar.bz2
2003-12-03 Alexandre Oliva <aoliva@redhat.com>
* config/tc-sh.c: Add support for sh4a and no-fpu variants, with appropriate additions to md_show_usage. * testsuite/gas/sh/basic.exp: Call tests for sh4a. * testsuite/gas/sh/{err-sh4a-fp.s, err-sh4a.s, err-sh4al-dsp.s, sh4a-dsp.d, sh4a-dsp.s, sh4a-fp.d, sh4a-fp.s, sh4a.d, sh4a.s, sh4al-dsp.d, sh4al-dsp.s: New files, tests for sh4a and related variants. * doc/c-sh.texi: Document new -isa options. * doc/c-sh64.texi: Ditto. * NEWS: Mention new support for sh4a.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-sh.c361
1 files changed, 346 insertions, 15 deletions
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index c499491..2b8f918 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -1400,13 +1400,13 @@ parse_at (char *src, sh_operand_info *op)
|| (l0 == 'i' && (l1 == 'x' || l1 == 's')))
{
src += 2;
- op->type = A_PMOD_N;
+ op->type = AX_PMOD_N;
}
else if ( (l0 == 'r' && l1 == '9')
|| (l0 == 'i' && l1 == 'y'))
{
src += 2;
- op->type = A_PMODY_N;
+ op->type = AY_PMOD_N;
}
else
op->type = A_INC_N;
@@ -1579,8 +1579,6 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *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)
@@ -1626,6 +1624,237 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
reg_m = user->reg;
break;
+ case AS_DEC_N:
+ if (user->type != A_DEC_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AS_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AS_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AS_PMOD_N:
+ if (user->type != AX_PMOD_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AX_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg < 4 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AX_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if (user->reg < 4 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AX_PMOD_N:
+ if (user->type != AX_PMOD_N)
+ goto fail;
+ if (user->reg < 4 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AXY_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if ((user->reg < 4 || user->reg > 5)
+ && (user->reg < 0 || user->reg > 1))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AXY_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if ((user->reg < 4 || user->reg > 5)
+ && (user->reg < 0 || user->reg > 1))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AXY_PMOD_N:
+ if (user->type != AX_PMOD_N)
+ goto fail;
+ if ((user->reg < 4 || user->reg > 5)
+ && (user->reg < 0 || user->reg > 1))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AY_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg < 6 || user->reg > 7)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AY_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if (user->reg < 6 || user->reg > 7)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AY_PMOD_N:
+ if (user->type != AY_PMOD_N)
+ goto fail;
+ if (user->reg < 6 || user->reg > 7)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AYX_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if ((user->reg < 6 || user->reg > 7)
+ && (user->reg < 2 || user->reg > 3))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AYX_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if ((user->reg < 6 || user->reg > 7)
+ && (user->reg < 2 || user->reg > 3))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AYX_PMOD_N:
+ if (user->type != AY_PMOD_N)
+ goto fail;
+ if ((user->reg < 6 || user->reg > 7)
+ && (user->reg < 2 || user->reg > 3))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case DSP_REG_A_M:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ if (user->reg != A_A0_NUM
+ && user->reg != A_A1_NUM)
+ goto fail;
+ reg_m = user->reg;
+ break;
+
+ case DSP_REG_AX:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_A0_NUM:
+ reg_x = 0;
+ break;
+ case A_A1_NUM:
+ reg_x = 2;
+ break;
+ case A_X0_NUM:
+ reg_x = 1;
+ break;
+ case A_X1_NUM:
+ reg_x = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_XY:
+ 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 = 2;
+ break;
+ case A_Y0_NUM:
+ reg_x = 1;
+ break;
+ case A_Y1_NUM:
+ reg_x = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_AY:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_A0_NUM:
+ reg_y = 0;
+ break;
+ case A_A1_NUM:
+ reg_y = 1;
+ break;
+ case A_Y0_NUM:
+ reg_y = 2;
+ break;
+ case A_Y1_NUM:
+ reg_y = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_YX:
+ 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_X0_NUM:
+ reg_y = 2;
+ break;
+ case A_X1_NUM:
+ reg_y = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
case DSP_REG_X:
if (user->type != DSP_REG_N)
goto fail;
@@ -2069,6 +2298,7 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
if (opcode->arg[0] != A_END)
op_end = get_operands (opcode, op_end, operand);
+ try_another_opcode:
opcode = get_specific (opcode, operand);
if (opcode == 0)
{
@@ -2099,9 +2329,43 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
movy = DDT_BASE;
break;
+ case MOVX_NOPY:
+ if (movx)
+ as_bad (_("multiple movx specifications"));
+ if ((reg_n < 4 || reg_n > 5)
+ && (reg_n < 0 || reg_n > 1))
+ as_bad (_("invalid movx address register"));
+ if (movy && movy != DDT_BASE)
+ as_bad (_("insn cannot be combined with non-nopy"));
+ movx = ((((reg_n & 1) != 0) << 9)
+ + (((reg_n & 4) == 0) << 8)
+ + (reg_x << 6)
+ + (opcode->nibbles[2] << 4)
+ + opcode->nibbles[3]
+ + DDT_BASE);
+ break;
+
+ case MOVY_NOPX:
+ if (movy)
+ as_bad (_("multiple movy specifications"));
+ if ((reg_n < 6 || reg_n > 7)
+ && (reg_n < 2 || reg_n > 3))
+ as_bad (_("invalid movy address register"));
+ if (movx && movx != DDT_BASE)
+ as_bad (_("insn cannot be combined with non-nopx"));
+ movy = ((((reg_n & 1) != 0) << 8)
+ + (((reg_n & 4) == 0) << 9)
+ + (reg_y << 6)
+ + (opcode->nibbles[2] << 4)
+ + opcode->nibbles[3]
+ + DDT_BASE);
+ break;
+
case MOVX:
if (movx)
as_bad (_("multiple movx specifications"));
+ if (movy & 0x2ac)
+ as_bad (_("previous movy requires nopx"));
if (reg_n < 4 || reg_n > 5)
as_bad (_("invalid movx address register"));
if (opcode->nibbles[2] & 8)
@@ -2123,6 +2387,8 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
case MOVY:
if (movy)
as_bad (_("multiple movy specifications"));
+ if (movx & 0x153)
+ as_bad (_("previous movx requires nopy"));
if (opcode->nibbles[2] & 8)
{
/* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,
@@ -2151,11 +2417,31 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
| (operand[0].immediate.X_add_number & 127) << 4
| reg_n);
break;
+ case PPI3NC:
+ if (cond)
+ {
+ opcode++;
+ goto try_another_opcode;
+ }
+ /* Fall through. */
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);
+ switch (opcode->nibbles[4])
+ {
+ case HEX_0:
+ case HEX_XX00:
+ case HEX_00YY:
+ break;
+ case HEX_1:
+ case HEX_4:
+ field_b += opcode->nibbles[4] << 4;
+ break;
+ default:
+ abort ();
+ }
break;
case PDC:
if (cond)
@@ -2170,13 +2456,34 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
+ cond + (reg_x << 6) + (reg_y << 4) + reg_n);
cond = 0;
+ switch (opcode->nibbles[4])
+ {
+ case HEX_0:
+ case HEX_XX00:
+ case HEX_00YY:
+ break;
+ case HEX_1:
+ case HEX_4:
+ field_b += opcode->nibbles[4] << 4;
+ break;
+ default:
+ abort ();
+ }
break;
case PMUL:
if (field_b)
{
- if ((field_b & 0xef00) != 0xa100)
+ if ((field_b & 0xef00) == 0xa100)
+ field_b -= 0x8100;
+ /* pclr Dz pmuls Se,Sf,Dg */
+ else if ((field_b & 0xff00) == 0x8d00
+ && (valid_arch & arch_sh4al_dsp_up))
+ {
+ valid_arch &= arch_sh4al_dsp_up;
+ field_b -= 0x8cf0;
+ }
+ else
as_bad (_("insn cannot be combined with pmuls"));
- field_b -= 0x8100;
switch (field_b & 0xf)
{
case A_X0_NUM:
@@ -2192,7 +2499,7 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
field_b += 3 - A_A1_NUM;
break;
default:
- as_bad (_("bad padd / psub pmuls output operand"));
+ as_bad (_("bad combined pmuls output operand"));
}
/* Generate warning if the destination register for padd / psub
and pmuls is the same ( only for A0 or A1 ).
@@ -2578,12 +2885,18 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
break;
case OPTION_DSP:
- preset_target_arch = arch_sh1_up & ~arch_sh3e_up;
+ preset_target_arch = arch_sh1_up & ~arch_sh2e_up;
break;
case OPTION_ISA:
if (strcasecmp (arg, "sh4") == 0)
preset_target_arch = arch_sh4;
+ else if (strcasecmp (arg, "sh4a") == 0)
+ preset_target_arch = arch_sh4a;
+ else if (strcasecmp (arg, "dsp") == 0)
+ preset_target_arch = arch_sh1_up & ~arch_sh2e_up;
+ else if (strcasecmp (arg, "fp") == 0)
+ preset_target_arch = arch_sh2e_up;
else if (strcasecmp (arg, "any") == 0)
preset_target_arch = arch_sh1_up;
#ifdef HAVE_SH64
@@ -2659,13 +2972,23 @@ SH options:\n\
-big generate big endian code\n\
-relax alter jump instructions for long displacements\n\
-small align sections to 4 byte boundaries, not 16\n\
--dsp enable sh-dsp insns, and disable sh2e/sh3e/sh4 insns.\n"));
+-dsp enable sh-dsp insns, and disable floating-point ISAs.\n"));
+ fprintf (stream, _("\
+-isa=[sh4\n\
+ | sh4a\n\
+ | dsp same as '-dsp'\n\
+ | fp\n"
+#ifdef HAVE_SH64
+"\
+ | shmedia set default instruction set for SH64\n\
+ | SHmedia\n\
+ | shcompact\n\
+ | SHcompact\n"
+#endif
+"\
+ | any]\n"));
#ifdef HAVE_SH64
fprintf (stream, _("\
--isa=[shmedia set default instruction set for SH64\n\
- | SHmedia\n\
- | shcompact\n\
- | SHcompact]\n\
-abi=[32|64] set size of expanded SHmedia operands and object\n\
file type\n\
-shcompact-const-crange emit code-range descriptors for constants in\n\
@@ -3212,7 +3535,7 @@ sh_elf_final_processing (void)
int val;
/* Set file-specific flags to indicate if this code needs
- a processor with the sh-dsp / sh3e ISA to execute. */
+ a processor with the sh-dsp / sh2e ISA to execute. */
#ifdef HAVE_SH64
/* SH5 and above don't know about the valid_arch arch_sh* bits defined
in sh-opc.h, so check SH64 mode before checking valid_arch. */
@@ -3231,11 +3554,19 @@ sh_elf_final_processing (void)
else if (valid_arch & arch_sh3)
val = EF_SH3;
else if (valid_arch & arch_sh3_dsp)
- val = EF_SH_DSP;
+ val = EF_SH3_DSP;
else if (valid_arch & arch_sh3e)
val = EF_SH3E;
+ else if (valid_arch & arch_sh4_nofpu)
+ val = EF_SH4_NOFPU;
else if (valid_arch & arch_sh4)
val = EF_SH4;
+ else if (valid_arch & arch_sh4a_nofpu)
+ val = EF_SH4A_NOFPU;
+ else if (valid_arch & arch_sh4a)
+ val = EF_SH4A;
+ else if (valid_arch & arch_sh4al_dsp)
+ val = EF_SH4AL_DSP;
else
abort ();