175fd0b74Schristos /* Print SPARC instructions.
2*e992f068Schristos Copyright (C) 1989-2022 Free Software Foundation, Inc.
375fd0b74Schristos
475fd0b74Schristos This file is part of the GNU opcodes library.
575fd0b74Schristos
675fd0b74Schristos This library is free software; you can redistribute it and/or modify
775fd0b74Schristos it under the terms of the GNU General Public License as published by
875fd0b74Schristos the Free Software Foundation; either version 3, or (at your option)
975fd0b74Schristos any later version.
1075fd0b74Schristos
1175fd0b74Schristos It is distributed in the hope that it will be useful, but WITHOUT
1275fd0b74Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1375fd0b74Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
1475fd0b74Schristos License for more details.
1575fd0b74Schristos
1675fd0b74Schristos You should have received a copy of the GNU General Public License
1775fd0b74Schristos along with this program; if not, write to the Free Software
1875fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
1975fd0b74Schristos MA 02110-1301, USA. */
2075fd0b74Schristos
2175fd0b74Schristos #include "sysdep.h"
2275fd0b74Schristos #include <stdio.h>
2375fd0b74Schristos #include "opcode/sparc.h"
2475fd0b74Schristos #include "dis-asm.h"
2575fd0b74Schristos #include "libiberty.h"
2675fd0b74Schristos #include "opintl.h"
2775fd0b74Schristos
2875fd0b74Schristos /* Bitmask of v9 architectures. */
2975fd0b74Schristos #define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
3075fd0b74Schristos | (1 << SPARC_OPCODE_ARCH_V9A) \
3175fd0b74Schristos | (1 << SPARC_OPCODE_ARCH_V9B) \
3275fd0b74Schristos | (1 << SPARC_OPCODE_ARCH_V9C) \
3375fd0b74Schristos | (1 << SPARC_OPCODE_ARCH_V9D) \
3475fd0b74Schristos | (1 << SPARC_OPCODE_ARCH_V9E) \
3575fd0b74Schristos | (1 << SPARC_OPCODE_ARCH_V9V) \
36ede78133Schristos | (1 << SPARC_OPCODE_ARCH_V9M) \
37ede78133Schristos | (1 << SPARC_OPCODE_ARCH_M8))
3875fd0b74Schristos /* 1 if INSN is for v9 only. */
3975fd0b74Schristos #define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
4075fd0b74Schristos /* 1 if INSN is for v9. */
4175fd0b74Schristos #define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)
4275fd0b74Schristos
4375fd0b74Schristos /* The sorted opcode table. */
4475fd0b74Schristos static const sparc_opcode **sorted_opcodes;
4575fd0b74Schristos
4675fd0b74Schristos /* For faster lookup, after insns are sorted they are hashed. */
4775fd0b74Schristos /* ??? I think there is room for even more improvement. */
4875fd0b74Schristos
4975fd0b74Schristos #define HASH_SIZE 256
5075fd0b74Schristos /* It is important that we only look at insn code bits as that is how the
5175fd0b74Schristos opcode table is hashed. OPCODE_BITS is a table of valid bits for each
5275fd0b74Schristos of the main types (0,1,2,3). */
5375fd0b74Schristos static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
5475fd0b74Schristos #define HASH_INSN(INSN) \
5575fd0b74Schristos ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
5675fd0b74Schristos typedef struct sparc_opcode_hash
5775fd0b74Schristos {
5875fd0b74Schristos struct sparc_opcode_hash *next;
5975fd0b74Schristos const sparc_opcode *opcode;
6075fd0b74Schristos } sparc_opcode_hash;
6175fd0b74Schristos
6275fd0b74Schristos static sparc_opcode_hash *opcode_hash_table[HASH_SIZE];
6375fd0b74Schristos
6475fd0b74Schristos /* Sign-extend a value which is N bits long. */
6575fd0b74Schristos #define SEX(value, bits) \
66012573ebSchristos ((int) (((value & ((1u << (bits - 1) << 1) - 1)) \
67012573ebSchristos ^ (1u << (bits - 1))) - (1u << (bits - 1))))
6875fd0b74Schristos
6975fd0b74Schristos static char *reg_names[] =
7075fd0b74Schristos { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
7175fd0b74Schristos "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
7275fd0b74Schristos "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
7375fd0b74Schristos "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
7475fd0b74Schristos "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
7575fd0b74Schristos "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
7675fd0b74Schristos "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
7775fd0b74Schristos "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
7875fd0b74Schristos "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
7975fd0b74Schristos "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
8075fd0b74Schristos "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
8175fd0b74Schristos "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
8275fd0b74Schristos /* psr, wim, tbr, fpsr, cpsr are v8 only. */
8375fd0b74Schristos "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"
8475fd0b74Schristos };
8575fd0b74Schristos
8675fd0b74Schristos #define freg_names (®_names[4 * 8])
8775fd0b74Schristos
8875fd0b74Schristos /* These are ordered according to there register number in
8975fd0b74Schristos rdpr and wrpr insns. */
9075fd0b74Schristos static char *v9_priv_reg_names[] =
9175fd0b74Schristos {
9275fd0b74Schristos "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
9375fd0b74Schristos "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
9475fd0b74Schristos "wstate", "fq", "gl"
9575fd0b74Schristos /* "ver" and "pmcdper" - special cased */
9675fd0b74Schristos };
9775fd0b74Schristos
9875fd0b74Schristos /* These are ordered according to there register number in
9975fd0b74Schristos rdhpr and wrhpr insns. */
10075fd0b74Schristos static char *v9_hpriv_reg_names[] =
10175fd0b74Schristos {
10275fd0b74Schristos "hpstate", "htstate", "resv2", "hintp", "resv4", "htba", "hver",
10375fd0b74Schristos "resv7", "resv8", "resv9", "resv10", "resv11", "resv12", "resv13",
10475fd0b74Schristos "resv14", "resv15", "resv16", "resv17", "resv18", "resv19", "resv20",
10575fd0b74Schristos "resv21", "resv22", "hmcdper", "hmcddfr", "resv25", "resv26", "hva_mask_nz",
10675fd0b74Schristos "hstick_offset", "hstick_enable", "resv30", "hstick_cmpr"
10775fd0b74Schristos };
10875fd0b74Schristos
10975fd0b74Schristos /* These are ordered according to there register number in
11075fd0b74Schristos rd and wr insns (-16). */
11175fd0b74Schristos static char *v9a_asr_reg_names[] =
11275fd0b74Schristos {
11375fd0b74Schristos "pcr", "pic", "dcr", "gsr", "softint_set", "softint_clear",
11475fd0b74Schristos "softint", "tick_cmpr", "stick", "stick_cmpr", "cfr",
11575fd0b74Schristos "pause", "mwait"
11675fd0b74Schristos };
11775fd0b74Schristos
11875fd0b74Schristos /* Macros used to extract instruction fields. Not all fields have
11975fd0b74Schristos macros defined here, only those which are actually used. */
12075fd0b74Schristos
12175fd0b74Schristos #define X_RD(i) (((i) >> 25) & 0x1f)
12275fd0b74Schristos #define X_RS1(i) (((i) >> 14) & 0x1f)
12375fd0b74Schristos #define X_LDST_I(i) (((i) >> 13) & 1)
12475fd0b74Schristos #define X_ASI(i) (((i) >> 5) & 0xff)
12575fd0b74Schristos #define X_RS2(i) (((i) >> 0) & 0x1f)
12675fd0b74Schristos #define X_RS3(i) (((i) >> 9) & 0x1f)
12775fd0b74Schristos #define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))
12875fd0b74Schristos #define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))
12975fd0b74Schristos #define X_DISP22(i) (((i) >> 0) & 0x3fffff)
13075fd0b74Schristos #define X_IMM22(i) X_DISP22 (i)
13175fd0b74Schristos #define X_DISP30(i) (((i) >> 0) & 0x3fffffff)
132ede78133Schristos #define X_IMM2(i) (((i & 0x10) >> 3) | (i & 0x1))
13375fd0b74Schristos
13475fd0b74Schristos /* These are for v9. */
13575fd0b74Schristos #define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))
13675fd0b74Schristos #define X_DISP10(i) (((((i) >> 19) & 3) << 8) | (((i) >> 5) & 0xff))
13775fd0b74Schristos #define X_DISP19(i) (((i) >> 0) & 0x7ffff)
13875fd0b74Schristos #define X_MEMBAR(i) ((i) & 0x7f)
13975fd0b74Schristos
14075fd0b74Schristos /* Here is the union which was used to extract instruction fields
14175fd0b74Schristos before the shift and mask macros were written.
14275fd0b74Schristos
14375fd0b74Schristos union sparc_insn
14475fd0b74Schristos {
14575fd0b74Schristos unsigned long int code;
14675fd0b74Schristos struct
14775fd0b74Schristos {
14875fd0b74Schristos unsigned int anop:2;
14975fd0b74Schristos #define op ldst.anop
15075fd0b74Schristos unsigned int anrd:5;
15175fd0b74Schristos #define rd ldst.anrd
15275fd0b74Schristos unsigned int op3:6;
15375fd0b74Schristos unsigned int anrs1:5;
15475fd0b74Schristos #define rs1 ldst.anrs1
15575fd0b74Schristos unsigned int i:1;
15675fd0b74Schristos unsigned int anasi:8;
15775fd0b74Schristos #define asi ldst.anasi
15875fd0b74Schristos unsigned int anrs2:5;
15975fd0b74Schristos #define rs2 ldst.anrs2
16075fd0b74Schristos #define shcnt rs2
16175fd0b74Schristos } ldst;
16275fd0b74Schristos struct
16375fd0b74Schristos {
16475fd0b74Schristos unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
16575fd0b74Schristos unsigned int IMM13:13;
16675fd0b74Schristos #define imm13 IMM13.IMM13
16775fd0b74Schristos } IMM13;
16875fd0b74Schristos struct
16975fd0b74Schristos {
17075fd0b74Schristos unsigned int anop:2;
17175fd0b74Schristos unsigned int a:1;
17275fd0b74Schristos unsigned int cond:4;
17375fd0b74Schristos unsigned int op2:3;
17475fd0b74Schristos unsigned int DISP22:22;
17575fd0b74Schristos #define disp22 branch.DISP22
17675fd0b74Schristos #define imm22 disp22
17775fd0b74Schristos } branch;
17875fd0b74Schristos struct
17975fd0b74Schristos {
18075fd0b74Schristos unsigned int anop:2;
18175fd0b74Schristos unsigned int a:1;
18275fd0b74Schristos unsigned int z:1;
18375fd0b74Schristos unsigned int rcond:3;
18475fd0b74Schristos unsigned int op2:3;
18575fd0b74Schristos unsigned int DISP16HI:2;
18675fd0b74Schristos unsigned int p:1;
18775fd0b74Schristos unsigned int _rs1:5;
18875fd0b74Schristos unsigned int DISP16LO:14;
18975fd0b74Schristos } branch16;
19075fd0b74Schristos struct
19175fd0b74Schristos {
19275fd0b74Schristos unsigned int anop:2;
19375fd0b74Schristos unsigned int adisp30:30;
19475fd0b74Schristos #define disp30 call.adisp30
19575fd0b74Schristos } call;
19675fd0b74Schristos }; */
19775fd0b74Schristos
19875fd0b74Schristos /* Nonzero if INSN is the opcode for a delayed branch. */
19975fd0b74Schristos
20075fd0b74Schristos static int
is_delayed_branch(unsigned long insn)20175fd0b74Schristos is_delayed_branch (unsigned long insn)
20275fd0b74Schristos {
20375fd0b74Schristos sparc_opcode_hash *op;
20475fd0b74Schristos
20575fd0b74Schristos for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
20675fd0b74Schristos {
20775fd0b74Schristos const sparc_opcode *opcode = op->opcode;
20875fd0b74Schristos
20975fd0b74Schristos if ((opcode->match & insn) == opcode->match
21075fd0b74Schristos && (opcode->lose & insn) == 0)
21175fd0b74Schristos return opcode->flags & F_DELAYED;
21275fd0b74Schristos }
21375fd0b74Schristos return 0;
21475fd0b74Schristos }
21575fd0b74Schristos
21675fd0b74Schristos /* extern void qsort (); */
21775fd0b74Schristos
21875fd0b74Schristos /* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value
21975fd0b74Schristos to compare_opcodes. */
22075fd0b74Schristos static unsigned int current_arch_mask;
22175fd0b74Schristos
22275fd0b74Schristos /* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */
22375fd0b74Schristos
22475fd0b74Schristos static int
compute_arch_mask(unsigned long mach)22575fd0b74Schristos compute_arch_mask (unsigned long mach)
22675fd0b74Schristos {
22775fd0b74Schristos switch (mach)
22875fd0b74Schristos {
22975fd0b74Schristos case 0 :
23075fd0b74Schristos case bfd_mach_sparc :
23175fd0b74Schristos return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)
23275fd0b74Schristos | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_LEON));
23375fd0b74Schristos case bfd_mach_sparc_sparclet :
23475fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);
23575fd0b74Schristos case bfd_mach_sparc_sparclite :
23675fd0b74Schristos case bfd_mach_sparc_sparclite_le :
23775fd0b74Schristos /* sparclites insns are recognized by default (because that's how
23875fd0b74Schristos they've always been treated, for better or worse). Kludge this by
23975fd0b74Schristos indicating generic v8 is also selected. */
24075fd0b74Schristos return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
24175fd0b74Schristos | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));
24275fd0b74Schristos case bfd_mach_sparc_v8plus :
24375fd0b74Schristos case bfd_mach_sparc_v9 :
24475fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);
24575fd0b74Schristos case bfd_mach_sparc_v8plusa :
24675fd0b74Schristos case bfd_mach_sparc_v9a :
24775fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
24875fd0b74Schristos case bfd_mach_sparc_v8plusb :
24975fd0b74Schristos case bfd_mach_sparc_v9b :
25075fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B);
25175fd0b74Schristos case bfd_mach_sparc_v8plusc :
25275fd0b74Schristos case bfd_mach_sparc_v9c :
25375fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9C);
25475fd0b74Schristos case bfd_mach_sparc_v8plusd :
25575fd0b74Schristos case bfd_mach_sparc_v9d :
25675fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9D);
25775fd0b74Schristos case bfd_mach_sparc_v8pluse :
25875fd0b74Schristos case bfd_mach_sparc_v9e :
25975fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9E);
26075fd0b74Schristos case bfd_mach_sparc_v8plusv :
26175fd0b74Schristos case bfd_mach_sparc_v9v :
26275fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9V);
26375fd0b74Schristos case bfd_mach_sparc_v8plusm :
26475fd0b74Schristos case bfd_mach_sparc_v9m :
26575fd0b74Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9M);
266ede78133Schristos case bfd_mach_sparc_v8plusm8 :
267ede78133Schristos case bfd_mach_sparc_v9m8 :
268ede78133Schristos return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_M8);
26975fd0b74Schristos }
27075fd0b74Schristos abort ();
27175fd0b74Schristos }
27275fd0b74Schristos
27375fd0b74Schristos /* Compare opcodes A and B. */
27475fd0b74Schristos
27575fd0b74Schristos static int
compare_opcodes(const void * a,const void * b)27675fd0b74Schristos compare_opcodes (const void * a, const void * b)
27775fd0b74Schristos {
27875fd0b74Schristos sparc_opcode *op0 = * (sparc_opcode **) a;
27975fd0b74Schristos sparc_opcode *op1 = * (sparc_opcode **) b;
28075fd0b74Schristos unsigned long int match0 = op0->match, match1 = op1->match;
28175fd0b74Schristos unsigned long int lose0 = op0->lose, lose1 = op1->lose;
28275fd0b74Schristos register unsigned int i;
28375fd0b74Schristos
28475fd0b74Schristos /* If one (and only one) insn isn't supported by the current architecture,
28575fd0b74Schristos prefer the one that is. If neither are supported, but they're both for
28675fd0b74Schristos the same architecture, continue processing. Otherwise (both unsupported
28775fd0b74Schristos and for different architectures), prefer lower numbered arch's (fudged
28875fd0b74Schristos by comparing the bitmasks). */
28975fd0b74Schristos if (op0->architecture & current_arch_mask)
29075fd0b74Schristos {
29175fd0b74Schristos if (! (op1->architecture & current_arch_mask))
29275fd0b74Schristos return -1;
29375fd0b74Schristos }
29475fd0b74Schristos else
29575fd0b74Schristos {
29675fd0b74Schristos if (op1->architecture & current_arch_mask)
29775fd0b74Schristos return 1;
29875fd0b74Schristos else if (op0->architecture != op1->architecture)
29975fd0b74Schristos return op0->architecture - op1->architecture;
30075fd0b74Schristos }
30175fd0b74Schristos
30275fd0b74Schristos /* If a bit is set in both match and lose, there is something
30375fd0b74Schristos wrong with the opcode table. */
30475fd0b74Schristos if (match0 & lose0)
30575fd0b74Schristos {
306ede78133Schristos opcodes_error_handler
30775fd0b74Schristos /* xgettext:c-format */
308ede78133Schristos (_("internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
30975fd0b74Schristos op0->name, match0, lose0);
31075fd0b74Schristos op0->lose &= ~op0->match;
31175fd0b74Schristos lose0 = op0->lose;
31275fd0b74Schristos }
31375fd0b74Schristos
31475fd0b74Schristos if (match1 & lose1)
31575fd0b74Schristos {
316ede78133Schristos opcodes_error_handler
31775fd0b74Schristos /* xgettext:c-format */
318ede78133Schristos (_("internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
31975fd0b74Schristos op1->name, match1, lose1);
32075fd0b74Schristos op1->lose &= ~op1->match;
32175fd0b74Schristos lose1 = op1->lose;
32275fd0b74Schristos }
32375fd0b74Schristos
32475fd0b74Schristos /* Because the bits that are variable in one opcode are constant in
32575fd0b74Schristos another, it is important to order the opcodes in the right order. */
32675fd0b74Schristos for (i = 0; i < 32; ++i)
32775fd0b74Schristos {
328012573ebSchristos unsigned long int x = 1ul << i;
32975fd0b74Schristos int x0 = (match0 & x) != 0;
33075fd0b74Schristos int x1 = (match1 & x) != 0;
33175fd0b74Schristos
33275fd0b74Schristos if (x0 != x1)
33375fd0b74Schristos return x1 - x0;
33475fd0b74Schristos }
33575fd0b74Schristos
33675fd0b74Schristos for (i = 0; i < 32; ++i)
33775fd0b74Schristos {
338012573ebSchristos unsigned long int x = 1ul << i;
33975fd0b74Schristos int x0 = (lose0 & x) != 0;
34075fd0b74Schristos int x1 = (lose1 & x) != 0;
34175fd0b74Schristos
34275fd0b74Schristos if (x0 != x1)
34375fd0b74Schristos return x1 - x0;
34475fd0b74Schristos }
34575fd0b74Schristos
34675fd0b74Schristos /* They are functionally equal. So as long as the opcode table is
34775fd0b74Schristos valid, we can put whichever one first we want, on aesthetic grounds. */
34875fd0b74Schristos
34975fd0b74Schristos /* Our first aesthetic ground is that aliases defer to real insns. */
35075fd0b74Schristos {
35175fd0b74Schristos int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
35275fd0b74Schristos
35375fd0b74Schristos if (alias_diff != 0)
35475fd0b74Schristos /* Put the one that isn't an alias first. */
35575fd0b74Schristos return alias_diff;
35675fd0b74Schristos }
35775fd0b74Schristos
35875fd0b74Schristos /* Except for aliases, two "identical" instructions had
35975fd0b74Schristos better have the same opcode. This is a sanity check on the table. */
36075fd0b74Schristos i = strcmp (op0->name, op1->name);
36175fd0b74Schristos if (i)
36275fd0b74Schristos {
36375fd0b74Schristos if (op0->flags & F_ALIAS)
36475fd0b74Schristos {
36575fd0b74Schristos if (op0->flags & F_PREFERRED)
36675fd0b74Schristos return -1;
36775fd0b74Schristos if (op1->flags & F_PREFERRED)
36875fd0b74Schristos return 1;
36975fd0b74Schristos
37075fd0b74Schristos /* If they're both aliases, and neither is marked as preferred,
37175fd0b74Schristos be arbitrary. */
37275fd0b74Schristos return i;
37375fd0b74Schristos }
37475fd0b74Schristos else
375ede78133Schristos opcodes_error_handler
37675fd0b74Schristos /* xgettext:c-format */
377ede78133Schristos (_("internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"),
37875fd0b74Schristos op0->name, op1->name);
37975fd0b74Schristos }
38075fd0b74Schristos
38175fd0b74Schristos /* Fewer arguments are preferred. */
38275fd0b74Schristos {
38375fd0b74Schristos int length_diff = strlen (op0->args) - strlen (op1->args);
38475fd0b74Schristos
38575fd0b74Schristos if (length_diff != 0)
38675fd0b74Schristos /* Put the one with fewer arguments first. */
38775fd0b74Schristos return length_diff;
38875fd0b74Schristos }
38975fd0b74Schristos
39075fd0b74Schristos /* Put 1+i before i+1. */
39175fd0b74Schristos {
39275fd0b74Schristos char *p0 = (char *) strchr (op0->args, '+');
39375fd0b74Schristos char *p1 = (char *) strchr (op1->args, '+');
39475fd0b74Schristos
39575fd0b74Schristos if (p0 && p1)
39675fd0b74Schristos {
39775fd0b74Schristos /* There is a plus in both operands. Note that a plus
39875fd0b74Schristos sign cannot be the first character in args,
39975fd0b74Schristos so the following [-1]'s are valid. */
40075fd0b74Schristos if (p0[-1] == 'i' && p1[1] == 'i')
40175fd0b74Schristos /* op0 is i+1 and op1 is 1+i, so op1 goes first. */
40275fd0b74Schristos return 1;
40375fd0b74Schristos if (p0[1] == 'i' && p1[-1] == 'i')
40475fd0b74Schristos /* op0 is 1+i and op1 is i+1, so op0 goes first. */
40575fd0b74Schristos return -1;
40675fd0b74Schristos }
40775fd0b74Schristos }
40875fd0b74Schristos
40975fd0b74Schristos /* Put 1,i before i,1. */
41075fd0b74Schristos {
41175fd0b74Schristos int i0 = strncmp (op0->args, "i,1", 3) == 0;
41275fd0b74Schristos int i1 = strncmp (op1->args, "i,1", 3) == 0;
41375fd0b74Schristos
41475fd0b74Schristos if (i0 ^ i1)
41575fd0b74Schristos return i0 - i1;
41675fd0b74Schristos }
41775fd0b74Schristos
41875fd0b74Schristos /* They are, as far as we can tell, identical.
41975fd0b74Schristos Since qsort may have rearranged the table partially, there is
42075fd0b74Schristos no way to tell which one was first in the opcode table as
42175fd0b74Schristos written, so just say there are equal. */
42275fd0b74Schristos /* ??? This is no longer true now that we sort a vector of pointers,
42375fd0b74Schristos not the table itself. */
42475fd0b74Schristos return 0;
42575fd0b74Schristos }
42675fd0b74Schristos
42775fd0b74Schristos /* Build a hash table from the opcode table.
42875fd0b74Schristos OPCODE_TABLE is a sorted list of pointers into the opcode table. */
42975fd0b74Schristos
43075fd0b74Schristos static void
build_hash_table(const sparc_opcode ** opcode_table,sparc_opcode_hash ** hash_table,int num_opcodes)43175fd0b74Schristos build_hash_table (const sparc_opcode **opcode_table,
43275fd0b74Schristos sparc_opcode_hash **hash_table,
43375fd0b74Schristos int num_opcodes)
43475fd0b74Schristos {
43575fd0b74Schristos int i;
43675fd0b74Schristos int hash_count[HASH_SIZE];
43775fd0b74Schristos static sparc_opcode_hash *hash_buf = NULL;
43875fd0b74Schristos
43975fd0b74Schristos /* Start at the end of the table and work backwards so that each
44075fd0b74Schristos chain is sorted. */
44175fd0b74Schristos
44275fd0b74Schristos memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
44375fd0b74Schristos memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));
44475fd0b74Schristos free (hash_buf);
44575fd0b74Schristos hash_buf = xmalloc (sizeof (* hash_buf) * num_opcodes);
44675fd0b74Schristos for (i = num_opcodes - 1; i >= 0; --i)
44775fd0b74Schristos {
44875fd0b74Schristos int hash = HASH_INSN (opcode_table[i]->match);
44975fd0b74Schristos sparc_opcode_hash *h = &hash_buf[i];
45075fd0b74Schristos
45175fd0b74Schristos h->next = hash_table[hash];
45275fd0b74Schristos h->opcode = opcode_table[i];
45375fd0b74Schristos hash_table[hash] = h;
45475fd0b74Schristos ++hash_count[hash];
45575fd0b74Schristos }
45675fd0b74Schristos
45775fd0b74Schristos #if 0 /* for debugging */
45875fd0b74Schristos {
45975fd0b74Schristos int min_count = num_opcodes, max_count = 0;
46075fd0b74Schristos int total;
46175fd0b74Schristos
46275fd0b74Schristos for (i = 0; i < HASH_SIZE; ++i)
46375fd0b74Schristos {
46475fd0b74Schristos if (hash_count[i] < min_count)
46575fd0b74Schristos min_count = hash_count[i];
46675fd0b74Schristos if (hash_count[i] > max_count)
46775fd0b74Schristos max_count = hash_count[i];
46875fd0b74Schristos total += hash_count[i];
46975fd0b74Schristos }
47075fd0b74Schristos
47175fd0b74Schristos printf ("Opcode hash table stats: min %d, max %d, ave %f\n",
47275fd0b74Schristos min_count, max_count, (double) total / HASH_SIZE);
47375fd0b74Schristos }
47475fd0b74Schristos #endif
47575fd0b74Schristos }
47675fd0b74Schristos
47775fd0b74Schristos /* Print one instruction from MEMADDR on INFO->STREAM.
47875fd0b74Schristos
47975fd0b74Schristos We suffix the instruction with a comment that gives the absolute
48075fd0b74Schristos address involved, as well as its symbolic form, if the instruction
48175fd0b74Schristos is preceded by a findable `sethi' and it either adds an immediate
48275fd0b74Schristos displacement to that register, or it is an `add' or `or' instruction
48375fd0b74Schristos on that register. */
48475fd0b74Schristos
48575fd0b74Schristos int
print_insn_sparc(bfd_vma memaddr,disassemble_info * info)48675fd0b74Schristos print_insn_sparc (bfd_vma memaddr, disassemble_info *info)
48775fd0b74Schristos {
48875fd0b74Schristos FILE *stream = info->stream;
48975fd0b74Schristos bfd_byte buffer[4];
49075fd0b74Schristos unsigned long insn;
49175fd0b74Schristos sparc_opcode_hash *op;
49275fd0b74Schristos /* Nonzero of opcode table has been initialized. */
49375fd0b74Schristos static int opcodes_initialized = 0;
49475fd0b74Schristos /* bfd mach number of last call. */
49575fd0b74Schristos static unsigned long current_mach = 0;
49675fd0b74Schristos bfd_vma (*getword) (const void *);
49775fd0b74Schristos
49875fd0b74Schristos if (!opcodes_initialized
49975fd0b74Schristos || info->mach != current_mach)
50075fd0b74Schristos {
50175fd0b74Schristos int i;
50275fd0b74Schristos
50375fd0b74Schristos current_arch_mask = compute_arch_mask (info->mach);
50475fd0b74Schristos
50575fd0b74Schristos if (!opcodes_initialized)
50675fd0b74Schristos sorted_opcodes =
50775fd0b74Schristos xmalloc (sparc_num_opcodes * sizeof (sparc_opcode *));
50875fd0b74Schristos /* Reset the sorted table so we can resort it. */
50975fd0b74Schristos for (i = 0; i < sparc_num_opcodes; ++i)
51075fd0b74Schristos sorted_opcodes[i] = &sparc_opcodes[i];
51175fd0b74Schristos qsort ((char *) sorted_opcodes, sparc_num_opcodes,
51275fd0b74Schristos sizeof (sorted_opcodes[0]), compare_opcodes);
51375fd0b74Schristos
51475fd0b74Schristos build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
51575fd0b74Schristos current_mach = info->mach;
51675fd0b74Schristos opcodes_initialized = 1;
51775fd0b74Schristos }
51875fd0b74Schristos
51975fd0b74Schristos {
52075fd0b74Schristos int status =
52175fd0b74Schristos (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
52275fd0b74Schristos
52375fd0b74Schristos if (status != 0)
52475fd0b74Schristos {
52575fd0b74Schristos (*info->memory_error_func) (status, memaddr, info);
52675fd0b74Schristos return -1;
52775fd0b74Schristos }
52875fd0b74Schristos }
52975fd0b74Schristos
53075fd0b74Schristos /* On SPARClite variants such as DANlite (sparc86x), instructions
53175fd0b74Schristos are always big-endian even when the machine is in little-endian mode. */
53275fd0b74Schristos if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)
53375fd0b74Schristos getword = bfd_getb32;
53475fd0b74Schristos else
53575fd0b74Schristos getword = bfd_getl32;
53675fd0b74Schristos
53775fd0b74Schristos insn = getword (buffer);
53875fd0b74Schristos
53975fd0b74Schristos info->insn_info_valid = 1; /* We do return this info. */
54075fd0b74Schristos info->insn_type = dis_nonbranch; /* Assume non branch insn. */
54175fd0b74Schristos info->branch_delay_insns = 0; /* Assume no delay. */
54275fd0b74Schristos info->target = 0; /* Assume no target known. */
54375fd0b74Schristos
54475fd0b74Schristos for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
54575fd0b74Schristos {
54675fd0b74Schristos const sparc_opcode *opcode = op->opcode;
54775fd0b74Schristos
54875fd0b74Schristos /* If the insn isn't supported by the current architecture, skip it. */
54975fd0b74Schristos if (! (opcode->architecture & current_arch_mask))
55075fd0b74Schristos continue;
55175fd0b74Schristos
55275fd0b74Schristos if ((opcode->match & insn) == opcode->match
55375fd0b74Schristos && (opcode->lose & insn) == 0)
55475fd0b74Schristos {
55575fd0b74Schristos /* Nonzero means that we have found an instruction which has
55675fd0b74Schristos the effect of adding or or'ing the imm13 field to rs1. */
55775fd0b74Schristos int imm_added_to_rs1 = 0;
55875fd0b74Schristos int imm_ored_to_rs1 = 0;
55975fd0b74Schristos
56075fd0b74Schristos /* Nonzero means that we have found a plus sign in the args
56175fd0b74Schristos field of the opcode table. */
56275fd0b74Schristos int found_plus = 0;
56375fd0b74Schristos
56475fd0b74Schristos /* Nonzero means we have an annulled branch. */
56575fd0b74Schristos int is_annulled = 0;
56675fd0b74Schristos
56775fd0b74Schristos /* Do we have an `add' or `or' instruction combining an
56875fd0b74Schristos immediate with rs1? */
56975fd0b74Schristos if (opcode->match == 0x80102000) /* or */
57075fd0b74Schristos imm_ored_to_rs1 = 1;
57175fd0b74Schristos if (opcode->match == 0x80002000) /* add */
57275fd0b74Schristos imm_added_to_rs1 = 1;
57375fd0b74Schristos
57475fd0b74Schristos if (X_RS1 (insn) != X_RD (insn)
57575fd0b74Schristos && strchr (opcode->args, 'r') != 0)
57675fd0b74Schristos /* Can't do simple format if source and dest are different. */
57775fd0b74Schristos continue;
57875fd0b74Schristos if (X_RS2 (insn) != X_RD (insn)
57975fd0b74Schristos && strchr (opcode->args, 'O') != 0)
58075fd0b74Schristos /* Can't do simple format if source and dest are different. */
58175fd0b74Schristos continue;
58275fd0b74Schristos
58375fd0b74Schristos (*info->fprintf_func) (stream, "%s", opcode->name);
58475fd0b74Schristos
58575fd0b74Schristos {
58675fd0b74Schristos const char *s;
58775fd0b74Schristos
58875fd0b74Schristos if (opcode->args[0] != ',')
58975fd0b74Schristos (*info->fprintf_func) (stream, " ");
59075fd0b74Schristos
59175fd0b74Schristos for (s = opcode->args; *s != '\0'; ++s)
59275fd0b74Schristos {
59375fd0b74Schristos while (*s == ',')
59475fd0b74Schristos {
59575fd0b74Schristos (*info->fprintf_func) (stream, ",");
59675fd0b74Schristos ++s;
59775fd0b74Schristos switch (*s)
59875fd0b74Schristos {
59975fd0b74Schristos case 'a':
60075fd0b74Schristos (*info->fprintf_func) (stream, "a");
60175fd0b74Schristos is_annulled = 1;
60275fd0b74Schristos ++s;
60375fd0b74Schristos continue;
60475fd0b74Schristos case 'N':
60575fd0b74Schristos (*info->fprintf_func) (stream, "pn");
60675fd0b74Schristos ++s;
60775fd0b74Schristos continue;
60875fd0b74Schristos
60975fd0b74Schristos case 'T':
61075fd0b74Schristos (*info->fprintf_func) (stream, "pt");
61175fd0b74Schristos ++s;
61275fd0b74Schristos continue;
61375fd0b74Schristos
61475fd0b74Schristos default:
61575fd0b74Schristos break;
61675fd0b74Schristos }
61775fd0b74Schristos }
61875fd0b74Schristos
61975fd0b74Schristos (*info->fprintf_func) (stream, " ");
62075fd0b74Schristos
62175fd0b74Schristos switch (*s)
62275fd0b74Schristos {
62375fd0b74Schristos case '+':
62475fd0b74Schristos found_plus = 1;
62575fd0b74Schristos /* Fall through. */
62675fd0b74Schristos
62775fd0b74Schristos default:
62875fd0b74Schristos (*info->fprintf_func) (stream, "%c", *s);
62975fd0b74Schristos break;
63075fd0b74Schristos
63175fd0b74Schristos case '#':
63275fd0b74Schristos (*info->fprintf_func) (stream, "0");
63375fd0b74Schristos break;
63475fd0b74Schristos
63575fd0b74Schristos #define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n])
63675fd0b74Schristos case '1':
63775fd0b74Schristos case 'r':
63875fd0b74Schristos reg (X_RS1 (insn));
63975fd0b74Schristos break;
64075fd0b74Schristos
64175fd0b74Schristos case '2':
64275fd0b74Schristos case 'O':
64375fd0b74Schristos reg (X_RS2 (insn));
64475fd0b74Schristos break;
64575fd0b74Schristos
64675fd0b74Schristos case 'd':
64775fd0b74Schristos reg (X_RD (insn));
64875fd0b74Schristos break;
64975fd0b74Schristos #undef reg
65075fd0b74Schristos
65175fd0b74Schristos #define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n])
65275fd0b74Schristos #define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
65375fd0b74Schristos case 'e':
65475fd0b74Schristos freg (X_RS1 (insn));
65575fd0b74Schristos break;
65675fd0b74Schristos case 'v': /* Double/even. */
65775fd0b74Schristos case 'V': /* Quad/multiple of 4. */
658ede78133Schristos case ';': /* Double/even multiple of 8 doubles. */
65975fd0b74Schristos fregx (X_RS1 (insn));
66075fd0b74Schristos break;
66175fd0b74Schristos
66275fd0b74Schristos case 'f':
66375fd0b74Schristos freg (X_RS2 (insn));
66475fd0b74Schristos break;
66575fd0b74Schristos case 'B': /* Double/even. */
66675fd0b74Schristos case 'R': /* Quad/multiple of 4. */
667ede78133Schristos case ':': /* Double/even multiple of 8 doubles. */
66875fd0b74Schristos fregx (X_RS2 (insn));
66975fd0b74Schristos break;
67075fd0b74Schristos
67175fd0b74Schristos case '4':
67275fd0b74Schristos freg (X_RS3 (insn));
67375fd0b74Schristos break;
67475fd0b74Schristos case '5': /* Double/even. */
67575fd0b74Schristos fregx (X_RS3 (insn));
67675fd0b74Schristos break;
67775fd0b74Schristos
67875fd0b74Schristos case 'g':
67975fd0b74Schristos freg (X_RD (insn));
68075fd0b74Schristos break;
68175fd0b74Schristos case 'H': /* Double/even. */
68275fd0b74Schristos case 'J': /* Quad/multiple of 4. */
68375fd0b74Schristos case '}': /* Double/even. */
68475fd0b74Schristos fregx (X_RD (insn));
68575fd0b74Schristos break;
686ede78133Schristos
687ede78133Schristos case '^': /* Double/even multiple of 8 doubles. */
688ede78133Schristos fregx (X_RD (insn) & ~0x6);
689ede78133Schristos break;
690ede78133Schristos
691ede78133Schristos case '\'': /* Double/even in FPCMPSHL. */
692ede78133Schristos fregx (X_RS2 (insn | 0x11));
693ede78133Schristos break;
694ede78133Schristos
69575fd0b74Schristos #undef freg
69675fd0b74Schristos #undef fregx
69775fd0b74Schristos
69875fd0b74Schristos #define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
69975fd0b74Schristos case 'b':
70075fd0b74Schristos creg (X_RS1 (insn));
70175fd0b74Schristos break;
70275fd0b74Schristos
70375fd0b74Schristos case 'c':
70475fd0b74Schristos creg (X_RS2 (insn));
70575fd0b74Schristos break;
70675fd0b74Schristos
70775fd0b74Schristos case 'D':
70875fd0b74Schristos creg (X_RD (insn));
70975fd0b74Schristos break;
71075fd0b74Schristos #undef creg
71175fd0b74Schristos
71275fd0b74Schristos case 'h':
71375fd0b74Schristos (*info->fprintf_func) (stream, "%%hi(%#x)",
714012573ebSchristos (unsigned) X_IMM22 (insn) << 10);
71575fd0b74Schristos break;
71675fd0b74Schristos
71775fd0b74Schristos case 'i': /* 13 bit immediate. */
71875fd0b74Schristos case 'I': /* 11 bit immediate. */
71975fd0b74Schristos case 'j': /* 10 bit immediate. */
72075fd0b74Schristos {
72175fd0b74Schristos int imm;
72275fd0b74Schristos
72375fd0b74Schristos if (*s == 'i')
72475fd0b74Schristos imm = X_SIMM (insn, 13);
72575fd0b74Schristos else if (*s == 'I')
72675fd0b74Schristos imm = X_SIMM (insn, 11);
72775fd0b74Schristos else
72875fd0b74Schristos imm = X_SIMM (insn, 10);
72975fd0b74Schristos
73075fd0b74Schristos /* Check to see whether we have a 1+i, and take
73175fd0b74Schristos note of that fact.
73275fd0b74Schristos
73375fd0b74Schristos Note: because of the way we sort the table,
73475fd0b74Schristos we will be matching 1+i rather than i+1,
73575fd0b74Schristos so it is OK to assume that i is after +,
73675fd0b74Schristos not before it. */
73775fd0b74Schristos if (found_plus)
73875fd0b74Schristos imm_added_to_rs1 = 1;
73975fd0b74Schristos
74075fd0b74Schristos if (imm <= 9)
74175fd0b74Schristos (*info->fprintf_func) (stream, "%d", imm);
74275fd0b74Schristos else
74375fd0b74Schristos (*info->fprintf_func) (stream, "%#x", imm);
74475fd0b74Schristos }
74575fd0b74Schristos break;
74675fd0b74Schristos
74775fd0b74Schristos case ')': /* 5 bit unsigned immediate from RS3. */
74875fd0b74Schristos (info->fprintf_func) (stream, "%#x", (unsigned int) X_RS3 (insn));
74975fd0b74Schristos break;
75075fd0b74Schristos
75175fd0b74Schristos case 'X': /* 5 bit unsigned immediate. */
75275fd0b74Schristos case 'Y': /* 6 bit unsigned immediate. */
75375fd0b74Schristos {
75475fd0b74Schristos int imm = X_IMM (insn, *s == 'X' ? 5 : 6);
75575fd0b74Schristos
75675fd0b74Schristos if (imm <= 9)
75775fd0b74Schristos (info->fprintf_func) (stream, "%d", imm);
75875fd0b74Schristos else
75975fd0b74Schristos (info->fprintf_func) (stream, "%#x", (unsigned) imm);
76075fd0b74Schristos }
76175fd0b74Schristos break;
76275fd0b74Schristos
76375fd0b74Schristos case '3':
76475fd0b74Schristos (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3));
76575fd0b74Schristos break;
76675fd0b74Schristos
76775fd0b74Schristos case 'K':
76875fd0b74Schristos {
76975fd0b74Schristos int mask = X_MEMBAR (insn);
77075fd0b74Schristos int bit = 0x40, printed_one = 0;
77175fd0b74Schristos const char *name;
77275fd0b74Schristos
77375fd0b74Schristos if (mask == 0)
77475fd0b74Schristos (info->fprintf_func) (stream, "0");
77575fd0b74Schristos else
77675fd0b74Schristos while (bit)
77775fd0b74Schristos {
77875fd0b74Schristos if (mask & bit)
77975fd0b74Schristos {
78075fd0b74Schristos if (printed_one)
78175fd0b74Schristos (info->fprintf_func) (stream, "|");
78275fd0b74Schristos name = sparc_decode_membar (bit);
78375fd0b74Schristos (info->fprintf_func) (stream, "%s", name);
78475fd0b74Schristos printed_one = 1;
78575fd0b74Schristos }
78675fd0b74Schristos bit >>= 1;
78775fd0b74Schristos }
78875fd0b74Schristos break;
78975fd0b74Schristos }
79075fd0b74Schristos
79175fd0b74Schristos case '=':
79275fd0b74Schristos info->target = memaddr + SEX (X_DISP10 (insn), 10) * 4;
79375fd0b74Schristos (*info->print_address_func) (info->target, info);
79475fd0b74Schristos break;
79575fd0b74Schristos
79675fd0b74Schristos case 'k':
79775fd0b74Schristos info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
79875fd0b74Schristos (*info->print_address_func) (info->target, info);
79975fd0b74Schristos break;
80075fd0b74Schristos
80175fd0b74Schristos case 'G':
80275fd0b74Schristos info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
80375fd0b74Schristos (*info->print_address_func) (info->target, info);
80475fd0b74Schristos break;
80575fd0b74Schristos
80675fd0b74Schristos case '6':
80775fd0b74Schristos case '7':
80875fd0b74Schristos case '8':
80975fd0b74Schristos case '9':
81075fd0b74Schristos (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
81175fd0b74Schristos break;
81275fd0b74Schristos
81375fd0b74Schristos case 'z':
81475fd0b74Schristos (*info->fprintf_func) (stream, "%%icc");
81575fd0b74Schristos break;
81675fd0b74Schristos
81775fd0b74Schristos case 'Z':
81875fd0b74Schristos (*info->fprintf_func) (stream, "%%xcc");
81975fd0b74Schristos break;
82075fd0b74Schristos
82175fd0b74Schristos case 'E':
82275fd0b74Schristos (*info->fprintf_func) (stream, "%%ccr");
82375fd0b74Schristos break;
82475fd0b74Schristos
82575fd0b74Schristos case 's':
82675fd0b74Schristos (*info->fprintf_func) (stream, "%%fprs");
82775fd0b74Schristos break;
82875fd0b74Schristos
82975fd0b74Schristos case '{':
83075fd0b74Schristos (*info->fprintf_func) (stream, "%%mcdper");
83175fd0b74Schristos break;
83275fd0b74Schristos
833ede78133Schristos case '&':
834ede78133Schristos (*info->fprintf_func) (stream, "%%entropy");
835ede78133Schristos break;
836ede78133Schristos
83775fd0b74Schristos case 'o':
83875fd0b74Schristos (*info->fprintf_func) (stream, "%%asi");
83975fd0b74Schristos break;
84075fd0b74Schristos
84175fd0b74Schristos case 'W':
84275fd0b74Schristos (*info->fprintf_func) (stream, "%%tick");
84375fd0b74Schristos break;
84475fd0b74Schristos
84575fd0b74Schristos case 'P':
84675fd0b74Schristos (*info->fprintf_func) (stream, "%%pc");
84775fd0b74Schristos break;
84875fd0b74Schristos
84975fd0b74Schristos case '?':
85075fd0b74Schristos if (X_RS1 (insn) == 31)
85175fd0b74Schristos (*info->fprintf_func) (stream, "%%ver");
85275fd0b74Schristos else if (X_RS1 (insn) == 23)
85375fd0b74Schristos (*info->fprintf_func) (stream, "%%pmcdper");
85475fd0b74Schristos else if ((unsigned) X_RS1 (insn) < 17)
85575fd0b74Schristos (*info->fprintf_func) (stream, "%%%s",
85675fd0b74Schristos v9_priv_reg_names[X_RS1 (insn)]);
85775fd0b74Schristos else
85875fd0b74Schristos (*info->fprintf_func) (stream, "%%reserved");
85975fd0b74Schristos break;
86075fd0b74Schristos
86175fd0b74Schristos case '!':
86275fd0b74Schristos if (X_RD (insn) == 31)
86375fd0b74Schristos (*info->fprintf_func) (stream, "%%ver");
86475fd0b74Schristos else if (X_RD (insn) == 23)
86575fd0b74Schristos (*info->fprintf_func) (stream, "%%pmcdper");
86675fd0b74Schristos else if ((unsigned) X_RD (insn) < 17)
86775fd0b74Schristos (*info->fprintf_func) (stream, "%%%s",
86875fd0b74Schristos v9_priv_reg_names[X_RD (insn)]);
86975fd0b74Schristos else
87075fd0b74Schristos (*info->fprintf_func) (stream, "%%reserved");
87175fd0b74Schristos break;
87275fd0b74Schristos
87375fd0b74Schristos case '$':
87475fd0b74Schristos if ((unsigned) X_RS1 (insn) < 32)
87575fd0b74Schristos (*info->fprintf_func) (stream, "%%%s",
87675fd0b74Schristos v9_hpriv_reg_names[X_RS1 (insn)]);
87775fd0b74Schristos else
87875fd0b74Schristos (*info->fprintf_func) (stream, "%%reserved");
87975fd0b74Schristos break;
88075fd0b74Schristos
88175fd0b74Schristos case '%':
88275fd0b74Schristos if ((unsigned) X_RD (insn) < 32)
88375fd0b74Schristos (*info->fprintf_func) (stream, "%%%s",
88475fd0b74Schristos v9_hpriv_reg_names[X_RD (insn)]);
88575fd0b74Schristos else
88675fd0b74Schristos (*info->fprintf_func) (stream, "%%reserved");
88775fd0b74Schristos break;
88875fd0b74Schristos
88975fd0b74Schristos case '/':
89075fd0b74Schristos if (X_RS1 (insn) < 16 || X_RS1 (insn) > 28)
89175fd0b74Schristos (*info->fprintf_func) (stream, "%%reserved");
89275fd0b74Schristos else
89375fd0b74Schristos (*info->fprintf_func) (stream, "%%%s",
89475fd0b74Schristos v9a_asr_reg_names[X_RS1 (insn)-16]);
89575fd0b74Schristos break;
89675fd0b74Schristos
89775fd0b74Schristos case '_':
89875fd0b74Schristos if (X_RD (insn) < 16 || X_RD (insn) > 28)
89975fd0b74Schristos (*info->fprintf_func) (stream, "%%reserved");
90075fd0b74Schristos else
90175fd0b74Schristos (*info->fprintf_func) (stream, "%%%s",
90275fd0b74Schristos v9a_asr_reg_names[X_RD (insn)-16]);
90375fd0b74Schristos break;
90475fd0b74Schristos
90575fd0b74Schristos case '*':
90675fd0b74Schristos {
90775fd0b74Schristos const char *name = sparc_decode_prefetch (X_RD (insn));
90875fd0b74Schristos
90975fd0b74Schristos if (name)
91075fd0b74Schristos (*info->fprintf_func) (stream, "%s", name);
91175fd0b74Schristos else
91275fd0b74Schristos (*info->fprintf_func) (stream, "%ld", X_RD (insn));
91375fd0b74Schristos break;
91475fd0b74Schristos }
91575fd0b74Schristos
91675fd0b74Schristos case 'M':
91775fd0b74Schristos (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn));
91875fd0b74Schristos break;
91975fd0b74Schristos
92075fd0b74Schristos case 'm':
92175fd0b74Schristos (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn));
92275fd0b74Schristos break;
92375fd0b74Schristos
92475fd0b74Schristos case 'L':
92575fd0b74Schristos info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
92675fd0b74Schristos (*info->print_address_func) (info->target, info);
92775fd0b74Schristos break;
92875fd0b74Schristos
92975fd0b74Schristos case 'n':
93075fd0b74Schristos (*info->fprintf_func)
93175fd0b74Schristos (stream, "%#x", SEX (X_DISP22 (insn), 22));
93275fd0b74Schristos break;
93375fd0b74Schristos
93475fd0b74Schristos case 'l':
93575fd0b74Schristos info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
93675fd0b74Schristos (*info->print_address_func) (info->target, info);
93775fd0b74Schristos break;
93875fd0b74Schristos
93975fd0b74Schristos case 'A':
94075fd0b74Schristos {
94175fd0b74Schristos const char *name = sparc_decode_asi (X_ASI (insn));
94275fd0b74Schristos
94375fd0b74Schristos if (name)
94475fd0b74Schristos (*info->fprintf_func) (stream, "%s", name);
94575fd0b74Schristos else
94675fd0b74Schristos (*info->fprintf_func) (stream, "(%ld)", X_ASI (insn));
94775fd0b74Schristos break;
94875fd0b74Schristos }
94975fd0b74Schristos
95075fd0b74Schristos case 'C':
95175fd0b74Schristos (*info->fprintf_func) (stream, "%%csr");
95275fd0b74Schristos break;
95375fd0b74Schristos
95475fd0b74Schristos case 'F':
95575fd0b74Schristos (*info->fprintf_func) (stream, "%%fsr");
95675fd0b74Schristos break;
95775fd0b74Schristos
95875fd0b74Schristos case '(':
95975fd0b74Schristos (*info->fprintf_func) (stream, "%%efsr");
96075fd0b74Schristos break;
96175fd0b74Schristos
96275fd0b74Schristos case 'p':
96375fd0b74Schristos (*info->fprintf_func) (stream, "%%psr");
96475fd0b74Schristos break;
96575fd0b74Schristos
96675fd0b74Schristos case 'q':
96775fd0b74Schristos (*info->fprintf_func) (stream, "%%fq");
96875fd0b74Schristos break;
96975fd0b74Schristos
97075fd0b74Schristos case 'Q':
97175fd0b74Schristos (*info->fprintf_func) (stream, "%%cq");
97275fd0b74Schristos break;
97375fd0b74Schristos
97475fd0b74Schristos case 't':
97575fd0b74Schristos (*info->fprintf_func) (stream, "%%tbr");
97675fd0b74Schristos break;
97775fd0b74Schristos
97875fd0b74Schristos case 'w':
97975fd0b74Schristos (*info->fprintf_func) (stream, "%%wim");
98075fd0b74Schristos break;
98175fd0b74Schristos
98275fd0b74Schristos case 'x':
98375fd0b74Schristos (*info->fprintf_func) (stream, "%ld",
98475fd0b74Schristos ((X_LDST_I (insn) << 8)
98575fd0b74Schristos + X_ASI (insn)));
98675fd0b74Schristos break;
98775fd0b74Schristos
988ede78133Schristos case '|': /* 2-bit immediate */
989ede78133Schristos (*info->fprintf_func) (stream, "%ld", X_IMM2 (insn));
990ede78133Schristos break;
991ede78133Schristos
99275fd0b74Schristos case 'y':
99375fd0b74Schristos (*info->fprintf_func) (stream, "%%y");
99475fd0b74Schristos break;
99575fd0b74Schristos
99675fd0b74Schristos case 'u':
99775fd0b74Schristos case 'U':
99875fd0b74Schristos {
99975fd0b74Schristos int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
100075fd0b74Schristos const char *name = sparc_decode_sparclet_cpreg (val);
100175fd0b74Schristos
100275fd0b74Schristos if (name)
100375fd0b74Schristos (*info->fprintf_func) (stream, "%s", name);
100475fd0b74Schristos else
100575fd0b74Schristos (*info->fprintf_func) (stream, "%%cpreg(%d)", val);
100675fd0b74Schristos break;
100775fd0b74Schristos }
100875fd0b74Schristos }
100975fd0b74Schristos }
101075fd0b74Schristos }
101175fd0b74Schristos
101275fd0b74Schristos /* If we are adding or or'ing something to rs1, then
101375fd0b74Schristos check to see whether the previous instruction was
101475fd0b74Schristos a sethi to the same register as in the sethi.
101575fd0b74Schristos If so, attempt to print the result of the add or
101675fd0b74Schristos or (in this context add and or do the same thing)
101775fd0b74Schristos and its symbolic value. */
101875fd0b74Schristos if (imm_ored_to_rs1 || imm_added_to_rs1)
101975fd0b74Schristos {
102075fd0b74Schristos unsigned long prev_insn;
102175fd0b74Schristos int errcode;
102275fd0b74Schristos
102375fd0b74Schristos if (memaddr >= 4)
102475fd0b74Schristos errcode =
102575fd0b74Schristos (*info->read_memory_func)
102675fd0b74Schristos (memaddr - 4, buffer, sizeof (buffer), info);
102775fd0b74Schristos else
102875fd0b74Schristos errcode = 1;
102975fd0b74Schristos
103075fd0b74Schristos prev_insn = getword (buffer);
103175fd0b74Schristos
103275fd0b74Schristos if (errcode == 0)
103375fd0b74Schristos {
103475fd0b74Schristos /* If it is a delayed branch, we need to look at the
103575fd0b74Schristos instruction before the delayed branch. This handles
103675fd0b74Schristos sequences such as:
103775fd0b74Schristos
103875fd0b74Schristos sethi %o1, %hi(_foo), %o1
103975fd0b74Schristos call _printf
104075fd0b74Schristos or %o1, %lo(_foo), %o1 */
104175fd0b74Schristos
104275fd0b74Schristos if (is_delayed_branch (prev_insn))
104375fd0b74Schristos {
104475fd0b74Schristos if (memaddr >= 8)
104575fd0b74Schristos errcode = (*info->read_memory_func)
104675fd0b74Schristos (memaddr - 8, buffer, sizeof (buffer), info);
104775fd0b74Schristos else
104875fd0b74Schristos errcode = 1;
104975fd0b74Schristos
105075fd0b74Schristos prev_insn = getword (buffer);
105175fd0b74Schristos }
105275fd0b74Schristos }
105375fd0b74Schristos
105475fd0b74Schristos /* If there was a problem reading memory, then assume
105575fd0b74Schristos the previous instruction was not sethi. */
105675fd0b74Schristos if (errcode == 0)
105775fd0b74Schristos {
105875fd0b74Schristos /* Is it sethi to the same register? */
105975fd0b74Schristos if ((prev_insn & 0xc1c00000) == 0x01000000
106075fd0b74Schristos && X_RD (prev_insn) == X_RS1 (insn))
106175fd0b74Schristos {
106275fd0b74Schristos (*info->fprintf_func) (stream, "\t! ");
1063012573ebSchristos info->target = (unsigned) X_IMM22 (prev_insn) << 10;
106475fd0b74Schristos if (imm_added_to_rs1)
106575fd0b74Schristos info->target += X_SIMM (insn, 13);
106675fd0b74Schristos else
106775fd0b74Schristos info->target |= X_SIMM (insn, 13);
106875fd0b74Schristos (*info->print_address_func) (info->target, info);
106975fd0b74Schristos info->insn_type = dis_dref;
107075fd0b74Schristos info->data_size = 4; /* FIXME!!! */
107175fd0b74Schristos }
107275fd0b74Schristos }
107375fd0b74Schristos }
107475fd0b74Schristos
107575fd0b74Schristos if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
107675fd0b74Schristos {
107775fd0b74Schristos /* FIXME -- check is_annulled flag. */
107875fd0b74Schristos (void) is_annulled;
107975fd0b74Schristos if (opcode->flags & F_UNBR)
108075fd0b74Schristos info->insn_type = dis_branch;
108175fd0b74Schristos if (opcode->flags & F_CONDBR)
108275fd0b74Schristos info->insn_type = dis_condbranch;
108375fd0b74Schristos if (opcode->flags & F_JSR)
108475fd0b74Schristos info->insn_type = dis_jsr;
108575fd0b74Schristos if (opcode->flags & F_DELAYED)
108675fd0b74Schristos info->branch_delay_insns = 1;
108775fd0b74Schristos }
108875fd0b74Schristos
108975fd0b74Schristos return sizeof (buffer);
109075fd0b74Schristos }
109175fd0b74Schristos }
109275fd0b74Schristos
109375fd0b74Schristos info->insn_type = dis_noninsn; /* Mark as non-valid instruction. */
109475fd0b74Schristos (*info->fprintf_func) (stream, _("unknown"));
109575fd0b74Schristos return sizeof (buffer);
109675fd0b74Schristos }
1097