1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
/* SPARC opcode support. -*- C -*-
Copyright (C) 2000 Red Hat, Inc.
This file is part of CGEN.
This file is copyrighted with the GNU General Public License.
See file COPYING for details. */
/* This file is an addendum to sparc.cpu. Heavy use of C code isn't
appropriate in .cpu files, so it resides here. This especially applies
to assembly/disassembly where parsing/printing can be quite involved.
Such things aren't really part of the specification of the cpu, per se,
so .cpu files provide the general framework and .opc files handle the
nitty-gritty details as necessary.
Each section is delimited with start and end markers.
<cpu>-opc.h additions use: "-- opc.h"
<cpu>-opc.c additions use: "-- opc.c"
<cpu>-asm.c additions use: "-- asm.c"
<cpu>-dis.c additions use: "-- dis.c"
*/
/* -- opc.h */
#undef CGEN_DIS_HASH_SIZE
#define CGEN_DIS_HASH_SIZE 256
#undef CGEN_DIS_HASH
extern const unsigned int sparc_cgen_opcode_bits[];
#define CGEN_DIS_HASH(buffer, insn) \
((((insn) >> 24) & 0xc0) \
| (((insn) & sparc_cgen_opcode_bits[((insn) >> 30) & 3]) >> 19))
/* -- */
/* -- asm.c */
/* It is important that we only look at insn code bits as that is how the
opcode table is hashed. OPCODE_BITS is a table of valid bits for each
of the main types (0,1,2,3). */
const unsigned int sparc_cgen_opcode_bits[4] = {
0x01c00000, 0x0, 0x01f80000, 0x01f80000
};
/* Handle %lo(). */
static const char *
parse_lo10 (cd, strp, opindex, valuep)
CGEN_CPU_DESC cd;
const char **strp;
int opindex;
long *valuep;
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (strncasecmp (*strp, "%lo(", 4) == 0)
{
*strp += 4;
errmsg = cgen_parse_address (od, strp, opindex, BFD_RELOC_LO10,
&result_type, &value);
if (**strp != ')')
return "missing `)'";
++*strp;
value &= 0x3ff;
*valuep = value;
return errmsg;
}
return cgen_parse_unsigned_integer (od, strp, opindex, valuep);
}
static const char *
parse_lo13 (cd, strp, opindex, valuep)
CGEN_CPU_DESC cd;
const char **strp;
int opindex;
long *valuep;
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (strncasecmp (*strp, "%lo(", 4) == 0)
{
*strp += 4;
errmsg = cgen_parse_address (od, strp, opindex, BFD_RELOC_LO10,
&result_type, &value);
if (**strp != ')')
return "missing `)'";
++*strp;
value &= 0x3ff;
*valuep = value;
return errmsg;
}
return cgen_parse_unsigned_integer (od, strp, opindex, valuep);
}
/* Handle %hi(). */
static const char *
parse_hi22 (cd, strp, opindex, valuep)
CGEN_CPU_DESC cd;
const char **strp;
int opindex;
unsigned long *valuep;
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (strncasecmp (*strp, "%hi(", 4) == 0)
{
*strp += 4;
errmsg = cgen_parse_address (od, strp, opindex, BFD_RELOC_HI22,
&result_type, &value);
if (**strp != ')')
return "missing `)'";
++*strp;
if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
value >>= 10;
*valuep = value;
return errmsg;
}
return cgen_parse_unsigned_integer (od, strp, opindex, valuep);
}
/* -- */
/* -- dis.c */
/* Include "%hi(foo)" in sethi output. */
static void
print_hi22 (cd, dis_info, value, attrs, pc, length)
CGEN_CPU_DESC cd;
PTR dis_info;
long value;
unsigned int attrs;
bfd_vma pc;
int length;
{
disassemble_info *info = (disassemble_info *) dis_info;
(*info->fprintf_func) (info->stream, "%%hi(0x%lx)", value << 10);
}
#undef CGEN_PRINT_INSN
#define CGEN_PRINT_INSN my_print_insn
static int
my_print_insn (cd, pc, info)
CGEN_CPU_DESC cd;
bfd_vma pc;
disassemble_info *info;
{
char buffer[CGEN_MAX_INSN_SIZE];
char *buf = buffer;
int status;
unsigned long insn_value;
int len;
/* Read the base part of the insn. */
status = (*info->read_memory_func) (pc, buf, 4, info);
if (status != 0)
{
(*info->memory_error_func) (status, pc, info);
return -1;
}
len = print_insn (od, pc, info, buf, 4);
if (len != 0)
return len;
/* CGEN doesn't handle this insn yet. Fall back on old way. */
return old_print_insn_sparc (pc, info);
}
/* -- */
|