/* Opcode table for the ARC.
- Copyright 1994 Free Software Foundation, Inc.
+ Copyright 1994, 1995 Free Software Foundation, Inc.
Contributed by Doug Evans (dje@cygnus.com).
This program is free software; you can redistribute it and/or modify
INSERT_FN (insert_cond);
INSERT_FN (insert_forcelimm);
INSERT_FN (insert_reladdr);
+INSERT_FN (insert_absaddr);
INSERT_FN (insert_unopmacro);
INSERT_FN (insert_multshift);
EXTRACT_FN (extract_reg);
EXTRACT_FN (extract_flag);
EXTRACT_FN (extract_cond);
+EXTRACT_FN (extract_reladdr);
EXTRACT_FN (extract_unopmacro);
EXTRACT_FN (extract_multshift);
'n' DELAY N field (nullify field)
'q' COND condition code field
'Q' FORCELIMM set `cond_p' to 1 to ensure a constant is a limm
- 'B' BRANCH branch address
+ 'B' BRANCH branch address (22 bit pc relative)
+ 'J' JUMP jump address (26 bit absolute)
'z' SIZE1 size field in ld a,[b,c]
'Z' SIZE10 size field in ld a,[b,shimm]
'y' SIZE22 size field in st c,[b,shimm]
'x' SIGN0 sign extend field ld a,[b,c]
'X' SIGN9 sign extend field ld a,[b,shimm]
- 'u' ADDRESS3 update field in ld a,[b,c]
- 'v' ADDRESS12 update field in ld a,[b,shimm]
- 'w' ADDRESS24 update field in st c,[b,shimm]
- 'D' CACHEBYPASS5 direct to memory enable (cache bypass) in ld a,[b,c]
- 'e' CACHEBYPASS14 direct to memory enable (cache bypass) in ld a,[b,shimm]
- 'E' CACHEBYPASS26 direct to memory enable (cache bypass) in st c,[b,shimm]
+ 'w' ADDRESS3 write-back field in ld a,[b,c]
+ 'W' ADDRESS12 write-back field in ld a,[b,shimm]
+ 'v' ADDRESS24 write-back field in st c,[b,shimm]
+ 'e' CACHEBYPASS5 cache bypass in ld a,[b,c]
+ 'E' CACHEBYPASS14 cache bypass in ld a,[b,shimm]
+ 'D' CACHEBYPASS26 cache bypass in st c,[b,shimm]
+ 'u' UNSIGNED unsigned multiply
+ 's' SATURATION saturation limit in audio arc mac insn
'U' UNOPMACRO fake operand to copy REGB to REGC for unop macros
- 'M' MULTSHIFT fake operand to check if target has multiply/shifter
The following modifiers may appear between the % and char (eg: %.f):
#define SHIMMFINISH (REGC + 1)
{ 'S', 9, 0, ARC_OPERAND_SIGNED + ARC_OPERAND_FAKE, insert_shimmfinish, 0 },
-/* fake operand used to insert limm value into most instructions */
+/* fake operand used to insert limm value into most instructions;
+ this is also used for .word handling */
#define LIMMFINISH (SHIMMFINISH + 1)
- { 'L', 32, 32, ARC_OPERAND_ABSOLUTE + ARC_OPERAND_FAKE, insert_limmfinish, 0 },
+ { 'L', 32, 32, ARC_OPERAND_ADDRESS + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE, insert_limmfinish, 0 },
/* shimm operand when there is no reg indicator (ld,st) */
#define SHIMMOFFSET (LIMMFINISH + 1)
#define FORCELIMM (COND + 1)
{ 'Q', 0, 0, ARC_OPERAND_FAKE, insert_forcelimm },
-/* branch address b, bl, and lp insns */
+/* branch address; b, bl, and lp insns */
#define BRANCH (FORCELIMM + 1)
- { 'B', 20, 7, ARC_OPERAND_RELATIVE + ARC_OPERAND_SIGNED, insert_reladdr },
+ { 'B', 20, 7, ARC_OPERAND_RELATIVE_BRANCH + ARC_OPERAND_SIGNED, insert_reladdr, extract_reladdr },
+
+/* jump address; j insn (this is basically the same as 'L' except that the
+ value is right shifted by 2); this is also used for .word handling */
+#define JUMP (BRANCH + 1)
+ { 'J', 24, 32, ARC_OPERAND_ABSOLUTE_BRANCH + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE, insert_absaddr },
/* size field, stored in bit 1,2 */
-#define SIZE1 (BRANCH + 1)
+#define SIZE1 (JUMP + 1)
{ 'z', 2, 1, ARC_OPERAND_SUFFIX },
/* size field, stored in bit 10,11 */
/* address write back, stored in bit 3 */
#define ADDRESS3 (SIGN9 + 1)
- { 'u', 1, 3, ARC_OPERAND_SUFFIX },
+ { 'w', 1, 3, ARC_OPERAND_SUFFIX },
/* address write back, stored in bit 12 */
#define ADDRESS12 (ADDRESS3 + 1)
- { 'v', 1, 12, ARC_OPERAND_SUFFIX },
+ { 'W', 1, 12, ARC_OPERAND_SUFFIX },
/* address write back, stored in bit 24 */
#define ADDRESS24 (ADDRESS12 + 1)
- { 'w', 1, 24, ARC_OPERAND_SUFFIX },
+ { 'v', 1, 24, ARC_OPERAND_SUFFIX },
-/* address write back, stored in bit 3 */
+/* cache bypass, stored in bit 5 */
#define CACHEBYPASS5 (ADDRESS24 + 1)
- { 'D', 1, 5, ARC_OPERAND_SUFFIX },
+ { 'e', 1, 5, ARC_OPERAND_SUFFIX },
-/* address write back, stored in bit 12 */
+/* cache bypass, stored in bit 14 */
#define CACHEBYPASS14 (CACHEBYPASS5 + 1)
- { 'e', 1, 14, ARC_OPERAND_SUFFIX },
+ { 'E', 1, 14, ARC_OPERAND_SUFFIX },
-/* address write back, stored in bit 24 */
+/* cache bypass, stored in bit 26 */
#define CACHEBYPASS26 (CACHEBYPASS14 + 1)
- { 'E', 1, 26, ARC_OPERAND_SUFFIX },
+ { 'D', 1, 26, ARC_OPERAND_SUFFIX },
+
+/* unsigned multiply */
+#define UNSIGNED (CACHEBYPASS26 + 1)
+ { 'u', 1, 27, ARC_OPERAND_SUFFIX },
+
+/* unsigned multiply */
+#define SATURATION (UNSIGNED + 1)
+ { 's', 1, 28, ARC_OPERAND_SUFFIX },
/* unop macro, used to copy REGB to REGC */
-#define UNOPMACRO (CACHEBYPASS26 + 1)
+#define UNOPMACRO (SATURATION + 1)
{ 'U', 6, ARC_SHIFT_REGC, ARC_OPERAND_FAKE, insert_unopmacro, extract_unopmacro },
-/* multiply/shifter detector */
-/* ??? Using ARC_OPERAND_FAKE this way is probably taking things too far. */
-#define MULTSHIFT (UNOPMACRO + 1)
- { 'M', 0, 0, ARC_OPERAND_FAKE, insert_multshift, extract_multshift },
-
/* '.' modifier ('.' required). */
-#define MODDOT (MULTSHIFT + 1)
+#define MODDOT (UNOPMACRO + 1)
{ '.', 1, 0, ARC_MOD_DOT },
/* Dummy 'r' modifier for the register table.
/* end of list place holder */
{ 0 }
};
-
+\f
/* Given a format letter, yields the index into `arc_operands'.
eg: arc_operand_map['a'] = REGA. */
unsigned char arc_operand_map[256];
Longer versions of insns must appear before shorter ones (if gas sees
"lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
- junk). */
+ junk).
+
+ This table is best viewed on a wide screen (161 columns).
+ I'd prefer to keep it this way. */
/* ??? This table also includes macros: asl, lsl, and mov. The ppc port has
a more general facility for dealing with macros which could be used if
together. */
const struct arc_opcode arc_opcodes[] = {
+ { "mac%u%.s%.q%.f %a,%b,%c%F%S%L", I(-4), I(24), ARC_MACH_AUDIO },
/* Note that "mov" is really an "and". */
{ "mov%.q%.f %a,%b%F%S%L%U", I(-1), I(12) },
- { "mul%M%.q%.f %a,%b,%c%F%S%L", I(-1), I(20) },
- { "mulu%M%.q%.f %a,%b,%c%F%S%L", I(-1), I(21) },
+ { "mul%u%.q%.f %a,%b,%c%F%S%L", I(-2), I(28), ARC_MACH_AUDIO },
+ /* ??? This insn allows an optional "0," preceding the args. */
+ /* We can't use %u here because it's not a suffix (the "64" is in the way). */
+ { "mul64%.q%.f %b,%c%F%S%L", I(-1)+A(-1), I(20)+A(-1), ARC_MACH_HOST+ARC_MACH_GRAPHICS },
+ { "mulu64%.q%.f %b,%c%F%S%L", I(-1)+A(-1), I(21)+A(-1), ARC_MACH_HOST+ARC_MACH_GRAPHICS },
{ "adc%.q%.f %a,%b,%c%F%S%L", I(-1), I(9) },
{ "add%.q%.f %a,%b,%c%F%S%L", I(-1), I(8) },
{ "and%.q%.f %a,%b,%c%F%S%L", I(-1), I(12) },
- { "asl%M%.q%.f %a,%b,%c%F%S%L", I(-1), I(16) },
+ { "asl%.q%.f %a,%b,%c%F%S%L", I(-1), I(16), ARC_MACH_HOST+ARC_MACH_GRAPHICS },
/* Note that "asl" is really an "add". */
{ "asl%.q%.f %a,%b%F%S%L%U", I(-1), I(8) },
- { "asr%M%.q%.f %a,%b,%c%F%S%L", I(-1), I(18) },
+ { "asr%.q%.f %a,%b,%c%F%S%L", I(-1), I(18), ARC_MACH_HOST+ARC_MACH_GRAPHICS },
{ "asr%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(1) },
{ "bic%.q%.f %a,%b,%c%F%S%L", I(-1), I(14) },
{ "b%q%.n %B", I(-1), I(4) },
{ "extw%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(8) },
{ "flag%.q %b%G%S%L", I(-1)+A(-1)+C(-1), I(3)+A(ARC_REG_SHIMM_UPDATE)+C(0) },
/* %Q: force cond_p=1 --> no shimm values */
- { "j%q%Q%.n%.f %b%L", I(-1)+A(-1)+C(-1)+R(-1,7,1), I(7)+A(0)+C(0)+R(0,7,1) },
+ /* ??? This insn allows an optional flags spec. */
+ { "j%q%Q%.n%.f %b%J", I(-1)+A(-1)+C(-1)+R(-1,7,1), I(7)+A(0)+C(0)+R(0,7,1) },
/* Put opcode 1 ld insns first so shimm gets prefered over limm. */
/* "[%b]" is before "[%b,%d]" so 0 offsets don't get printed. */
- { "ld%Z%.X%.v%.e %0%a,[%b]%L", I(-1)+R(-1,13,1)+R(-1,0,511), I(1)+R(0,13,1)+R(0,0,511) },
- { "ld%Z%.X%.v%.e %a,[%b,%d]%S%L", I(-1)+R(-1,13,1), I(1)+R(0,13,1) },
- { "ld%z%.x%.u%.D %a,[%b,%c]", I(-1)+R(-1,4,1)+R(-1,6,7), I(0)+R(0,4,1)+R(0,6,7) },
+ { "ld%Z%.X%.W%.E %0%a,[%b]%L", I(-1)+R(-1,13,1)+R(-1,0,511), I(1)+R(0,13,1)+R(0,0,511) },
+ { "ld%Z%.X%.W%.E %a,[%b,%d]%S%L", I(-1)+R(-1,13,1), I(1)+R(0,13,1) },
+ { "ld%z%.x%.w%.e %a,[%b,%c]", I(-1)+R(-1,4,1)+R(-1,6,7), I(0)+R(0,4,1)+R(0,6,7) },
{ "lp%q%.n %B", I(-1), I(6), },
{ "lr %a,[%Ab]%S%L", I(-1)+C(-1), I(1)+C(0x10) },
/* Note that "lsl" is really an "add". */
{ "lsl%.q%.f %a,%b%F%S%L%U", I(-1), I(8) },
- { "lsr%M%.q%.f %a,%b,%c%F%S%L", I(-1), I(17) },
+ { "lsr%.q%.f %a,%b,%c%F%S%L", I(-1), I(17), ARC_MACH_HOST+ARC_MACH_GRAPHICS },
{ "lsr%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(2) },
/* Note that "nop" is really an "xor". */
{ "nop", 0xffffffff, 0x7fffffff },
{ "or%.q%.f %a,%b,%c%F%S%L", I(-1), I(13) },
+ /* ??? The %a here should be %p or something. */
+ { "padc%.q%.f %a,%b,%c%F%S%L", I(-1), I(25), ARC_MACH_GRAPHICS },
+ { "padd%.q%.f %a,%b,%c%F%S%L", I(-1), I(24), ARC_MACH_GRAPHICS },
+ /* Note that "pmov" is really a "pand". */
+ { "pmov%.q%.f %a,%b%F%S%L%U", I(-1), I(28), ARC_MACH_GRAPHICS },
+ { "pand%.q%.f %a,%b,%c%F%S%L", I(-1), I(28), ARC_MACH_GRAPHICS },
+ { "psbc%.q%.f %a,%b,%c%F%S%L", I(-1), I(27), ARC_MACH_GRAPHICS },
+ { "psub%.q%.f %a,%b,%c%F%S%L", I(-1), I(26), ARC_MACH_GRAPHICS },
/* Note that "rlc" is really an "adc". */
{ "rlc%.q%.f %a,%b%F%S%L%U", I(-1), I(9) },
- { "ror%M%.q%.f %a,%b,%c%F%S%L", I(-1), I(19) },
+ { "ror%.q%.f %a,%b,%c%F%S%L", I(-1), I(19), ARC_MACH_HOST+ARC_MACH_GRAPHICS },
{ "ror%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(3) },
{ "rrc%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(4) },
{ "sbc%.q%.f %a,%b,%c%F%S%L", I(-1), I(11) },
{ "sexw%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(6) },
{ "sr %c,[%Ab]%S%L", I(-1)+A(-1), I(2)+A(0x10) },
/* "[%b]" is before "[%b,%d]" so 0 offsets don't get printed. */
- { "st%y%.w%.E %0%c,[%b]%L", I(-1)+R(-1,25,3)+R(-1,21,1)+R(-1,0,511), I(2)+R(0,25,3)+R(0,21,1)+R(0,0,511) },
- { "st%y%.w%.E %c,[%b,%d]%S%L", I(-1)+R(-1,25,3)+R(-1,21,1), I(2)+R(0,25,3)+R(0,21,1) },
+ { "st%y%.v%.D %0%c,[%b]%L", I(-1)+R(-1,25,3)+R(-1,21,1)+R(-1,0,511), I(2)+R(0,25,3)+R(0,21,1)+R(0,0,511) },
+ { "st%y%.v%.D %c,[%b,%d]%S%L", I(-1)+R(-1,25,3)+R(-1,21,1), I(2)+R(0,25,3)+R(0,21,1) },
{ "sub%.q%.f %a,%b,%c%F%S%L", I(-1), I(10) },
+ { "swap%.q%.f %a,%b%F%S%L", I(-1)+C(-1), I(3)+C(9), ARC_MACH_AUDIO },
{ "xor%.q%.f %a,%b,%c%F%S%L", I(-1), I(15) }
};
-int arc_opcodes_count = sizeof (arc_opcodes) / sizeof (arc_opcodes[0]);
+const int arc_opcodes_count = sizeof (arc_opcodes) / sizeof (arc_opcodes[0]);
const struct arc_operand_value arc_reg_names[] =
{
{ "r27", 27, REG }, { "r28", 28, REG },
/* Standard auxiliary registers. */
- { "status", 0, AUXREG },
+ { "status", 0, AUXREG },
{ "semaphore", 1, AUXREG },
- { "lp_start", 2, AUXREG },
- { "lp_end", 3, AUXREG },
- { "identity", 4, AUXREG },
- { "debug", 5, AUXREG },
+ { "lp_start", 2, AUXREG },
+ { "lp_end", 3, AUXREG },
+ { "identity", 4, AUXREG },
+ { "debug", 5, AUXREG },
+
+ /* Host ARC Extensions. */
+ { "mlo", 57, REG, ARC_MACH_HOST },
+ { "mmid", 58, REG, ARC_MACH_HOST },
+ { "mhi", 59, REG, ARC_MACH_HOST },
+ { "ivic", 0x10, AUXREG, ARC_MACH_HOST },
+ { "ivdc", 0x11, AUXREG, ARC_MACH_HOST },
+ { "ivdcn", 0x12, AUXREG, ARC_MACH_HOST },
+ { "flushd", 0x13, AUXREG, ARC_MACH_HOST },
+ { "saha", 0x14, AUXREG, ARC_MACH_HOST },
+ { "gahd", 0x15, AUXREG, ARC_MACH_HOST },
+ { "aahd", 0x16, AUXREG, ARC_MACH_HOST },
+ { "rrcr", 0x17, AUXREG, ARC_MACH_HOST },
+ { "rpcr", 0x18, AUXREG, ARC_MACH_HOST },
+ { "flushdn", 0x19, AUXREG, ARC_MACH_HOST },
+ { "dbgad1", 0x1a, AUXREG, ARC_MACH_HOST },
+ { "dbgad2", 0x1b, AUXREG, ARC_MACH_HOST },
+ { "dbgmde", 0x1c, AUXREG, ARC_MACH_HOST },
+ { "dbgstat", 0x1d, AUXREG, ARC_MACH_HOST },
+ { "wag", 0x1e, AUXREG, ARC_MACH_HOST },
+ { "mulhi", 0x1f, AUXREG, ARC_MACH_HOST },
+ { "intwide", 0x20, AUXREG, ARC_MACH_HOST },
+ { "intgen", 0x21, AUXREG, ARC_MACH_HOST },
+ { "rfsh_n", 0x22, AUXREG, ARC_MACH_HOST },
+
+ /* Graphics ARC Extensions. */
+ { "mlo", 57, REG, ARC_MACH_GRAPHICS },
+ { "mmid", 58, REG, ARC_MACH_GRAPHICS },
+ { "mhi", 59, REG, ARC_MACH_GRAPHICS },
+ { "ivic", 0x10, AUXREG, ARC_MACH_GRAPHICS },
+ { "wag", 0x1e, AUXREG, ARC_MACH_GRAPHICS },
+ { "mulhi", 0x1f, AUXREG, ARC_MACH_GRAPHICS },
+ { "intwide", 0x20, AUXREG, ARC_MACH_GRAPHICS },
+ { "intgen", 0x21, AUXREG, ARC_MACH_GRAPHICS },
+ { "pix", 0x100, AUXREG, ARC_MACH_GRAPHICS },
+ { "scratch", 0x120, AUXREG, ARC_MACH_GRAPHICS },
+
+ /* Audio ARC Extensions. */
+ { "macmode", 39, REG, ARC_MACH_AUDIO },
+ { "rs1", 40, REG, ARC_MACH_AUDIO },
+ { "rs1n", 41, REG, ARC_MACH_AUDIO },
+ { "rs1start", 42, REG, ARC_MACH_AUDIO },
+ { "rs1size", 43, REG, ARC_MACH_AUDIO },
+ { "rs1delta", 44, REG, ARC_MACH_AUDIO },
+ { "rs1pos", 45, REG, ARC_MACH_AUDIO },
+ { "rd1", 46, REG, ARC_MACH_AUDIO },
+ { "rd1n", 47, REG, ARC_MACH_AUDIO },
+ { "rd1d", 48, REG, ARC_MACH_AUDIO },
+ { "rd1pos", 49, REG, ARC_MACH_AUDIO },
+ { "rs2", 50, REG, ARC_MACH_AUDIO },
+ { "rs2n", 51, REG, ARC_MACH_AUDIO },
+ { "rs2start", 52, REG, ARC_MACH_AUDIO },
+ { "rs2size", 53, REG, ARC_MACH_AUDIO },
+ { "rs2delta", 54, REG, ARC_MACH_AUDIO },
+ { "rs2pos", 55, REG, ARC_MACH_AUDIO },
+ { "rd2", 56, REG, ARC_MACH_AUDIO },
+ { "rd2n", 57, REG, ARC_MACH_AUDIO },
+ { "rd2d", 58, REG, ARC_MACH_AUDIO },
+ { "rd2pos", 59, REG, ARC_MACH_AUDIO },
+ { "ivic", 0x10, AUXREG, ARC_MACH_AUDIO },
+ { "wag", 0x1e, AUXREG, ARC_MACH_AUDIO },
+ { "intwide", 0x20, AUXREG, ARC_MACH_AUDIO },
+ { "intgen", 0x21, AUXREG, ARC_MACH_AUDIO },
+ { "bm_sstart", 0x30, AUXREG, ARC_MACH_AUDIO },
+ { "bm_length", 0x31, AUXREG, ARC_MACH_AUDIO },
+ { "bm_rstart", 0x32, AUXREG, ARC_MACH_AUDIO },
+ { "bm_go", 0x33, AUXREG, ARC_MACH_AUDIO },
+ { "xtp_newval", 0x40, AUXREG, ARC_MACH_AUDIO },
+ { "sram", 0x400, AUXREG, ARC_MACH_AUDIO },
+ { "reg_file", 0x800, AUXREG, ARC_MACH_AUDIO },
};
-int arc_reg_names_count = sizeof (arc_reg_names) / sizeof (arc_reg_names[0]);
+const int arc_reg_names_count = sizeof (arc_reg_names) / sizeof (arc_reg_names[0]);
/* The suffix table.
Operands with the same name must be stored together. */
{ "nd", 0, DELAY },
{ "d", 1, DELAY },
{ "jd", 2, DELAY },
-/* { "b", 7, SIZEEXT },*/
-/* { "b", 5, SIZESEX },*/
+/*{ "b", 7, SIZEEXT },*/
+/*{ "b", 5, SIZESEX },*/
{ "b", 1, SIZE1 },
{ "b", 1, SIZE10 },
{ "b", 1, SIZE22 },
-/* { "w", 8, SIZEEXT },*/
-/* { "w", 6, SIZESEX },*/
+/*{ "w", 8, SIZEEXT },*/
+/*{ "w", 6, SIZESEX },*/
{ "w", 2, SIZE1 },
{ "w", 2, SIZE10 },
{ "w", 2, SIZE22 },
{ "di", 1, CACHEBYPASS5 },
{ "di", 1, CACHEBYPASS14 },
{ "di", 1, CACHEBYPASS26 },
-};
-int arc_suffixes_count = sizeof (arc_suffixes) / sizeof (arc_suffixes[0]);
+ /* Audio ARC Extensions. */
+ /* ??? The values here are guesses. */
+ { "ss", 16, COND, ARC_MACH_AUDIO },
+ { "sc", 17, COND, ARC_MACH_AUDIO },
+ { "mh", 18, COND, ARC_MACH_AUDIO },
+ { "ml", 19, COND, ARC_MACH_AUDIO },
+};
+const int arc_suffixes_count = sizeof (arc_suffixes) / sizeof (arc_suffixes[0]);
+\f
/* Configuration flags. */
/* Various ARC_HAVE_XXX bits. */
static int cpu_type;
+/* Translate a bfd_mach_arc_xxx value to a ARC_MACH_XXX value. */
+
+int
+arc_get_opcode_mach (bfd_mach, big_p)
+ int bfd_mach, big_p;
+{
+ static int mach_type_map[] =
+ {
+ ARC_MACH_BASE, ARC_MACH_HOST, ARC_MACH_GRAPHICS, ARC_MACH_AUDIO
+ };
+
+ return mach_type_map[bfd_mach] | (big_p ? ARC_MACH_BIG : 0);
+}
+
/* Initialize any tables that need it.
Must be called once at start up (or when first needed).
- CPU is a set of bits that say what version of the cpu we have. */
+ FLAGS is a set of bits that say what version of the cpu we have,
+ and in particular at least (one of) ARC_MACH_XXX. */
void
-arc_opcode_init_tables (cpu)
- int cpu;
+arc_opcode_init_tables (flags)
+ int flags;
{
register int i,n;
+ static int map_init_p = 0;
- memset (arc_operand_map, 0, sizeof (arc_operand_map));
- n = sizeof (arc_operands) / sizeof (arc_operands[0]);
- for (i = 0; i < n; i++)
- arc_operand_map[arc_operands[i].fmt] = i;
+ cpu_type = flags;
- cpu_type = cpu;
+ /* We may be intentionally called more than once (for example gdb will call
+ us each time the user switches cpu). This table only needs to be init'd
+ once though. */
+ if (!map_init_p)
+ {
+ memset (arc_operand_map, 0, sizeof (arc_operand_map));
+ n = sizeof (arc_operands) / sizeof (arc_operands[0]);
+ for (i = 0; i < n; i++)
+ arc_operand_map[arc_operands[i].fmt] = i;
+ map_init_p = 1;
+ }
+}
+
+/* Return non-zero if OPCODE is supported on the specified cpu.
+ Cpu selection is made when calling `arc_opcode_init_tables'. */
+
+int
+arc_opcode_supported (opcode)
+ const struct arc_opcode *opcode;
+{
+ if (ARC_OPCODE_CPU (opcode->flags) == 0)
+ return 1;
+ if (ARC_OPCODE_CPU (opcode->flags) & ARC_HAVE_CPU (cpu_type))
+ return 1;
+ return 0;
+}
+
+/* Return non-zero if OPVAL is supported on the specified cpu.
+ Cpu selection is made when calling `arc_opcode_init_tables'. */
+
+int
+arc_opval_supported (opval)
+ const struct arc_operand_value *opval;
+{
+ if (ARC_OPVAL_CPU (opval->flags) == 0)
+ return 1;
+ if (ARC_OPVAL_CPU (opval->flags) & ARC_HAVE_CPU (cpu_type))
+ return 1;
+ return 0;
}
\f
/* Nonzero if we've seen an 'f' suffix (in certain insns). */
/* The value of the limm we inserted. Each insn only gets one but it can
appear multiple times. */
static long limm;
+\f
+/* Insertion functions. */
/* Called by the assembler before parsing an instruction. */
}
/* Called at the end of processing normal insns (eg: add) to insert a limm
- value (if present) into the insn. Actually, there's nothing for us to do
- as we can't call frag_more, the caller must do that. */
-/* ??? The extract fns take a pointer to two words. The insert insns could be
- converted and then we could do something useful. Not sure it's worth it. */
+ value (if present) into the insn.
+
+ Note that this function is only intended to handle instructions (with 4 byte
+ immediate operands). It is not intended to handle data. */
+
+/* ??? Actually, there's nothing for us to do as we can't call frag_more, the
+ caller must do that. The extract fns take a pointer to two words. The
+ insert fns could be converted and then we could do something useful, but
+ then the reloc handlers would have to know to work on the second word of
+ a 2 word quantity. That's too much so we don't handle them. */
static arc_insn
insert_limmfinish (insn, operand, mods, reg, value, errmsg)
const char **errmsg;
{
if (limm_p)
- ; /* nothing to do */
+ /* FIXME: put an abort here and see what happens. */
+ ; /* nothing to do, gas does it */
return insn;
}
long value;
const char **errmsg;
{
- /* FIXME: Addresses are stored * 4. Do we want to handle that here? */
- insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;
+ if (value & 3)
+ *errmsg = "branch address not on 4 byte boundary";
+ insn |= ((value >> 2) & ((1 << operand->bits) - 1)) << operand->shift;
return insn;
}
-/* Fake operand to disallow the multiply and variable shift insns if the cpu
- doesn't have them. */
+/* Insert a limm value as a 26 bit address right shifted 2 into the insn.
+
+ Note that this function is only intended to handle instructions (with 4 byte
+ immediate operands). It is not intended to handle data. */
+
+/* ??? Actually, there's nothing for us to do as we can't call frag_more, the
+ caller must do that. The extract fns take a pointer to two words. The
+ insert fns could be converted and then we could do something useful, but
+ then the reloc handlers would have to know to work on the second word of
+ a 2 word quantity. That's too much so we don't handle them. */
static arc_insn
-insert_multshift (insn, operand, mods, reg, value, errmsg)
+insert_absaddr (insn, operand, mods, reg, value, errmsg)
arc_insn insn;
const struct arc_operand *operand;
int mods;
long value;
const char **errmsg;
{
- if (!(cpu_type & ARC_HAVE_MULT_SHIFT))
- *errmsg = "cpu doesn't support this insn";
+ if (limm_p)
+ /* FIXME: put an abort here and see what happens. */
+ ; /* nothing to do */
return insn;
}
\f
cond = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
val = arc_opcode_lookup_suffix (operand, cond);
- /* Ignore NULL values of `val'. Several condition code values aren't
- implemented yet. */
+ /* Ignore NULL values of `val'. Several condition code values are
+ reserved for extensions. */
if (opval && val)
*opval = val;
return cond;
}
+/* Extract a branch address.
+ We return the value as a real address (not right shifted by 2). */
+
+static long
+extract_reladdr (insn, operand, mods, opval, invalid)
+ arc_insn *insn;
+ const struct arc_operand *operand;
+ int mods;
+ const struct arc_operand_value **opval;
+ int *invalid;
+{
+ long addr;
+
+ addr = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
+ if ((operand->flags & ARC_OPERAND_SIGNED)
+ && (addr & (1 << (operand->bits - 1))))
+ addr -= 1 << operand->bits;
+
+ return addr << 2;
+}
+
/* The only thing this does is set the `invalid' flag if B != C.
This is needed because the "mov" macro appears before it's real insn "and"
and we don't want the disassembler to confuse them. */
return 0;
}
-/* Don't recognize the multiply and variable shift insns if the cpu doesn't
- have them.
-
- ??? Actually, we probably should anyway. */
-
-static long
-extract_multshift (insn, operand, mods, opval, invalid)
- arc_insn *insn;
- const struct arc_operand *operand;
- int mods;
- const struct arc_operand_value **opval;
- int *invalid;
-{
- return 0;
-}
-
/* Utility for the extraction functions to return the index into
`arc_suffixes'. */