1 1.1.1.4 christos /* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */ 2 1.1 christos /* Disassembler interface for targets using CGEN. -*- C -*- 3 1.1 christos CGEN: Cpu tools GENerator 4 1.1 christos 5 1.1 christos THIS FILE IS MACHINE GENERATED WITH CGEN. 6 1.1 christos - the resultant file is machine generated, cgen-dis.in isn't 7 1.1 christos 8 1.1.1.10 christos Copyright (C) 1996-2026 Free Software Foundation, Inc. 9 1.1 christos 10 1.1 christos This file is part of libopcodes. 11 1.1 christos 12 1.1 christos This library is free software; you can redistribute it and/or modify 13 1.1 christos it under the terms of the GNU General Public License as published by 14 1.1 christos the Free Software Foundation; either version 3, or (at your option) 15 1.1 christos any later version. 16 1.1 christos 17 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT 18 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 19 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 20 1.1 christos License for more details. 21 1.1 christos 22 1.1 christos You should have received a copy of the GNU General Public License 23 1.1 christos along with this program; if not, write to the Free Software Foundation, Inc., 24 1.1 christos 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 25 1.1 christos 26 1.1 christos /* ??? Eventually more and more of this stuff can go to cpu-independent files. 27 1.1 christos Keep that in mind. */ 28 1.1 christos 29 1.1 christos #include "sysdep.h" 30 1.1 christos #include <stdio.h> 31 1.1 christos #include "ansidecl.h" 32 1.1.1.4 christos #include "disassemble.h" 33 1.1 christos #include "bfd.h" 34 1.1 christos #include "symcat.h" 35 1.1 christos #include "libiberty.h" 36 1.1 christos #include "epiphany-desc.h" 37 1.1 christos #include "epiphany-opc.h" 38 1.1 christos #include "opintl.h" 39 1.1 christos 40 1.1 christos /* Default text to print if an instruction isn't recognized. */ 41 1.1 christos #define UNKNOWN_INSN_MSG _("*unknown*") 42 1.1 christos 43 1.1 christos static void print_normal 44 1.1 christos (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int); 45 1.1 christos static void print_address 46 1.1 christos (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED; 47 1.1 christos static void print_keyword 48 1.1 christos (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED; 49 1.1 christos static void print_insn_normal 50 1.1 christos (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int); 51 1.1 christos static int print_insn 52 1.1 christos (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned); 53 1.1 christos static int default_print_insn 54 1.1 christos (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED; 55 1.1 christos static int read_insn 56 1.1 christos (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *, 57 1.1 christos unsigned long *); 58 1.1 christos 59 1.1 christos /* -- disassembler routines inserted here. */ 61 1.1 christos 62 1.1 christos /* -- dis.c */ 63 1.1 christos 64 1.1 christos #define CGEN_PRINT_INSN epiphany_print_insn 65 1.1 christos 66 1.1 christos static int 67 1.1 christos epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) 68 1.1 christos { 69 1.1 christos bfd_byte buf[CGEN_MAX_INSN_SIZE]; 70 1.1 christos int buflen; 71 1.1 christos int status; 72 1.1 christos 73 1.1.1.3 christos info->bytes_per_chunk = 2; 74 1.1 christos info->bytes_per_line = 4; 75 1.1 christos 76 1.1.1.3 christos /* Attempt to read the base part of the insn. */ 77 1.1 christos buflen = cd->base_insn_bitsize / 8; 78 1.1 christos status = (*info->read_memory_func) (pc, buf, buflen, info); 79 1.1 christos 80 1.1 christos /* Try again with the minimum part, if min < base. */ 81 1.1 christos if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 82 1.1.1.3 christos { 83 1.1 christos buflen = cd->min_insn_bitsize / 8; 84 1.1 christos status = (*info->read_memory_func) (pc, buf, buflen, info); 85 1.1 christos } 86 1.1 christos 87 1.1 christos if (status != 0) 88 1.1 christos { 89 1.1 christos (*info->memory_error_func) (status, pc, info); 90 1.1 christos return -1; 91 1.1 christos } 92 1.1 christos 93 1.1 christos return print_insn (cd, pc, info, buf, buflen); 94 1.1 christos } 95 1.1 christos 96 1.1 christos 97 1.1 christos static void 98 1.1 christos print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 99 1.1 christos void * dis_info, 100 1.1 christos long value, 101 1.1 christos unsigned int attrs ATTRIBUTE_UNUSED, 102 1.1 christos bfd_vma pc ATTRIBUTE_UNUSED, 103 1.1 christos int length ATTRIBUTE_UNUSED) 104 1.1 christos { 105 1.1 christos disassemble_info *info = (disassemble_info *) dis_info; 106 1.1 christos (*info->fprintf_func) (info->stream, value ? "-" : "+"); 107 1.1 christos } 108 1.1 christos 109 1.1 christos static void 110 1.1 christos print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 111 1.1 christos void * dis_info, 112 1.1 christos long value, 113 1.1 christos unsigned int attrs ATTRIBUTE_UNUSED, 114 1.1 christos bfd_vma pc ATTRIBUTE_UNUSED, 115 1.1 christos int length ATTRIBUTE_UNUSED) 116 1.1 christos { 117 1.1 christos print_address (cd, dis_info, value, attrs, pc, length); 118 1.1 christos } 119 1.1 christos 120 1.1 christos static void 121 1.1 christos print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 122 1.1 christos void * dis_info, 123 1.1 christos unsigned long value, 124 1.1 christos unsigned int attrs ATTRIBUTE_UNUSED, 125 1.1 christos bfd_vma pc ATTRIBUTE_UNUSED, 126 1.1 christos int length ATTRIBUTE_UNUSED) 127 1.1 christos { 128 1.1 christos disassemble_info *info = (disassemble_info *)dis_info; 129 1.1 christos 130 1.1 christos if (value & 0x800) 131 1.1 christos (*info->fprintf_func) (info->stream, "-"); 132 1.1 christos 133 1.1 christos value &= 0x7ff; 134 1.1 christos print_address (cd, dis_info, value, attrs, pc, length); 135 1.1 christos } 136 1.1 christos 137 1.1 christos 138 1.1 christos /* -- */ 140 1.1.1.7 christos 141 1.1 christos void epiphany_cgen_print_operand 142 1.1 christos (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int); 143 1.1 christos 144 1.1 christos /* Main entry point for printing operands. 145 1.1 christos XINFO is a `void *' and not a `disassemble_info *' to not put a requirement 146 1.1 christos of dis-asm.h on cgen.h. 147 1.1 christos 148 1.1 christos This function is basically just a big switch statement. Earlier versions 149 1.1 christos used tables to look up the function to use, but 150 1.1 christos - if the table contains both assembler and disassembler functions then 151 1.1 christos the disassembler contains much of the assembler and vice-versa, 152 1.1 christos - there's a lot of inlining possibilities as things grow, 153 1.1 christos - using a switch statement avoids the function call overhead. 154 1.1 christos 155 1.1 christos This function could be moved into `print_insn_normal', but keeping it 156 1.1 christos separate makes clear the interface between `print_insn_normal' and each of 157 1.1 christos the handlers. */ 158 1.1 christos 159 1.1 christos void 160 1.1 christos epiphany_cgen_print_operand (CGEN_CPU_DESC cd, 161 1.1 christos int opindex, 162 1.1 christos void * xinfo, 163 1.1 christos CGEN_FIELDS *fields, 164 1.1 christos void const *attrs ATTRIBUTE_UNUSED, 165 1.1 christos bfd_vma pc, 166 1.1 christos int length) 167 1.1 christos { 168 1.1 christos disassemble_info *info = (disassemble_info *) xinfo; 169 1.1 christos 170 1.1 christos switch (opindex) 171 1.1 christos { 172 1.1 christos case EPIPHANY_OPERAND_DIRECTION : 173 1.1 christos print_postindex (cd, info, fields->f_addsubx, 0, pc, length); 174 1.1 christos break; 175 1.1 christos case EPIPHANY_OPERAND_DISP11 : 176 1.1 christos print_uimm_not_reg (cd, info, fields->f_disp11, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length); 177 1.1 christos break; 178 1.1 christos case EPIPHANY_OPERAND_DISP3 : 179 1.1 christos print_normal (cd, info, fields->f_disp3, 0, pc, length); 180 1.1 christos break; 181 1.1 christos case EPIPHANY_OPERAND_DPMI : 182 1.1 christos print_postindex (cd, info, fields->f_subd, 0, pc, length); 183 1.1 christos break; 184 1.1 christos case EPIPHANY_OPERAND_FRD : 185 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0); 186 1.1 christos break; 187 1.1 christos case EPIPHANY_OPERAND_FRD6 : 188 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 189 1.1 christos break; 190 1.1 christos case EPIPHANY_OPERAND_FRM : 191 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0); 192 1.1 christos break; 193 1.1 christos case EPIPHANY_OPERAND_FRM6 : 194 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 195 1.1 christos break; 196 1.1 christos case EPIPHANY_OPERAND_FRN : 197 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0); 198 1.1 christos break; 199 1.1 christos case EPIPHANY_OPERAND_FRN6 : 200 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 201 1.1 christos break; 202 1.1 christos case EPIPHANY_OPERAND_IMM16 : 203 1.1 christos print_address (cd, info, fields->f_imm16, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length); 204 1.1 christos break; 205 1.1 christos case EPIPHANY_OPERAND_IMM8 : 206 1.1 christos print_address (cd, info, fields->f_imm8, 0|(1<<CGEN_OPERAND_RELAX), pc, length); 207 1.1 christos break; 208 1.1 christos case EPIPHANY_OPERAND_RD : 209 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0); 210 1.1 christos break; 211 1.1 christos case EPIPHANY_OPERAND_RD6 : 212 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 213 1.1 christos break; 214 1.1 christos case EPIPHANY_OPERAND_RM : 215 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0); 216 1.1 christos break; 217 1.1 christos case EPIPHANY_OPERAND_RM6 : 218 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 219 1.1 christos break; 220 1.1 christos case EPIPHANY_OPERAND_RN : 221 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0); 222 1.1 christos break; 223 1.1 christos case EPIPHANY_OPERAND_RN6 : 224 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 225 1.1 christos break; 226 1.1 christos case EPIPHANY_OPERAND_SD : 227 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd, 0); 228 1.1 christos break; 229 1.1 christos case EPIPHANY_OPERAND_SD6 : 230 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 231 1.1 christos break; 232 1.1 christos case EPIPHANY_OPERAND_SDDMA : 233 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 234 1.1 christos break; 235 1.1 christos case EPIPHANY_OPERAND_SDMEM : 236 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 237 1.1 christos break; 238 1.1 christos case EPIPHANY_OPERAND_SDMESH : 239 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 240 1.1 christos break; 241 1.1 christos case EPIPHANY_OPERAND_SHIFT : 242 1.1 christos print_normal (cd, info, fields->f_shift, 0, pc, length); 243 1.1 christos break; 244 1.1 christos case EPIPHANY_OPERAND_SIMM11 : 245 1.1 christos print_simm_not_reg (cd, info, fields->f_sdisp11, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length); 246 1.1 christos break; 247 1.1 christos case EPIPHANY_OPERAND_SIMM24 : 248 1.1 christos print_address (cd, info, fields->f_simm24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length); 249 1.1 christos break; 250 1.1 christos case EPIPHANY_OPERAND_SIMM3 : 251 1.1 christos print_simm_not_reg (cd, info, fields->f_sdisp3, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX), pc, length); 252 1.1 christos break; 253 1.1 christos case EPIPHANY_OPERAND_SIMM8 : 254 1.1 christos print_address (cd, info, fields->f_simm8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length); 255 1.1 christos break; 256 1.1 christos case EPIPHANY_OPERAND_SN : 257 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn, 0); 258 1.1 christos break; 259 1.1 christos case EPIPHANY_OPERAND_SN6 : 260 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 261 1.1 christos break; 262 1.1 christos case EPIPHANY_OPERAND_SNDMA : 263 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 264 1.1 christos break; 265 1.1 christos case EPIPHANY_OPERAND_SNMEM : 266 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 267 1.1 christos break; 268 1.1 christos case EPIPHANY_OPERAND_SNMESH : 269 1.1 christos print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL)); 270 1.1 christos break; 271 1.1 christos case EPIPHANY_OPERAND_SWI_NUM : 272 1.1 christos print_uimm_not_reg (cd, info, fields->f_trap_num, 0, pc, length); 273 1.1 christos break; 274 1.1 christos case EPIPHANY_OPERAND_TRAPNUM6 : 275 1.1 christos print_normal (cd, info, fields->f_trap_num, 0, pc, length); 276 1.1 christos break; 277 1.1 christos 278 1.1.1.5 christos default : 279 1.1.1.5 christos /* xgettext:c-format */ 280 1.1.1.5 christos opcodes_error_handler 281 1.1.1.5 christos (_("internal error: unrecognized field %d while printing insn"), 282 1.1 christos opindex); 283 1.1 christos abort (); 284 1.1 christos } 285 1.1.1.2 christos } 286 1.1 christos 287 1.1 christos cgen_print_fn * const epiphany_cgen_print_handlers[] = 288 1.1 christos { 289 1.1 christos print_insn_normal, 290 1.1 christos }; 291 1.1 christos 292 1.1 christos 293 1.1 christos void 294 1.1 christos epiphany_cgen_init_dis (CGEN_CPU_DESC cd) 295 1.1 christos { 296 1.1 christos epiphany_cgen_init_opcode_table (cd); 297 1.1 christos epiphany_cgen_init_ibld_table (cd); 298 1.1 christos cd->print_handlers = & epiphany_cgen_print_handlers[0]; 299 1.1 christos cd->print_operand = epiphany_cgen_print_operand; 300 1.1 christos } 301 1.1 christos 302 1.1 christos 303 1.1 christos /* Default print handler. */ 305 1.1 christos 306 1.1 christos static void 307 1.1 christos print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 308 1.1 christos void *dis_info, 309 1.1 christos long value, 310 1.1 christos unsigned int attrs, 311 1.1 christos bfd_vma pc ATTRIBUTE_UNUSED, 312 1.1 christos int length ATTRIBUTE_UNUSED) 313 1.1 christos { 314 1.1 christos disassemble_info *info = (disassemble_info *) dis_info; 315 1.1 christos 316 1.1 christos /* Print the operand as directed by the attributes. */ 317 1.1 christos if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) 318 1.1 christos ; /* nothing to do */ 319 1.1 christos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) 320 1.1 christos (*info->fprintf_func) (info->stream, "%ld", value); 321 1.1 christos else 322 1.1 christos (*info->fprintf_func) (info->stream, "0x%lx", value); 323 1.1 christos } 324 1.1 christos 325 1.1 christos /* Default address handler. */ 326 1.1 christos 327 1.1 christos static void 328 1.1 christos print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 329 1.1 christos void *dis_info, 330 1.1 christos bfd_vma value, 331 1.1 christos unsigned int attrs, 332 1.1 christos bfd_vma pc ATTRIBUTE_UNUSED, 333 1.1 christos int length ATTRIBUTE_UNUSED) 334 1.1 christos { 335 1.1 christos disassemble_info *info = (disassemble_info *) dis_info; 336 1.1 christos 337 1.1 christos /* Print the operand as directed by the attributes. */ 338 1.1 christos if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) 339 1.1 christos ; /* Nothing to do. */ 340 1.1 christos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR)) 341 1.1 christos (*info->print_address_func) (value, info); 342 1.1 christos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR)) 343 1.1 christos (*info->print_address_func) (value, info); 344 1.1 christos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) 345 1.1 christos (*info->fprintf_func) (info->stream, "%ld", (long) value); 346 1.1 christos else 347 1.1 christos (*info->fprintf_func) (info->stream, "0x%lx", (long) value); 348 1.1 christos } 349 1.1 christos 350 1.1 christos /* Keyword print handler. */ 351 1.1 christos 352 1.1 christos static void 353 1.1 christos print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 354 1.1 christos void *dis_info, 355 1.1 christos CGEN_KEYWORD *keyword_table, 356 1.1 christos long value, 357 1.1 christos unsigned int attrs ATTRIBUTE_UNUSED) 358 1.1 christos { 359 1.1 christos disassemble_info *info = (disassemble_info *) dis_info; 360 1.1 christos const CGEN_KEYWORD_ENTRY *ke; 361 1.1 christos 362 1.1 christos ke = cgen_keyword_lookup_value (keyword_table, value); 363 1.1 christos if (ke != NULL) 364 1.1 christos (*info->fprintf_func) (info->stream, "%s", ke->name); 365 1.1 christos else 366 1.1 christos (*info->fprintf_func) (info->stream, "???"); 367 1.1 christos } 368 1.1 christos 369 1.1 christos /* Default insn printer. 371 1.1 christos 372 1.1 christos DIS_INFO is defined as `void *' so the disassembler needn't know anything 373 1.1 christos about disassemble_info. */ 374 1.1 christos 375 1.1 christos static void 376 1.1 christos print_insn_normal (CGEN_CPU_DESC cd, 377 1.1 christos void *dis_info, 378 1.1 christos const CGEN_INSN *insn, 379 1.1 christos CGEN_FIELDS *fields, 380 1.1 christos bfd_vma pc, 381 1.1 christos int length) 382 1.1 christos { 383 1.1 christos const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 384 1.1 christos disassemble_info *info = (disassemble_info *) dis_info; 385 1.1 christos const CGEN_SYNTAX_CHAR_TYPE *syn; 386 1.1 christos 387 1.1 christos CGEN_INIT_PRINT (cd); 388 1.1 christos 389 1.1 christos for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) 390 1.1 christos { 391 1.1 christos if (CGEN_SYNTAX_MNEMONIC_P (*syn)) 392 1.1 christos { 393 1.1 christos (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn)); 394 1.1 christos continue; 395 1.1 christos } 396 1.1 christos if (CGEN_SYNTAX_CHAR_P (*syn)) 397 1.1 christos { 398 1.1 christos (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn)); 399 1.1 christos continue; 400 1.1 christos } 401 1.1 christos 402 1.1 christos /* We have an operand. */ 403 1.1 christos epiphany_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info, 404 1.1 christos fields, CGEN_INSN_ATTRS (insn), pc, length); 405 1.1 christos } 406 1.1 christos } 407 1.1 christos 408 1.1 christos /* Subroutine of print_insn. Reads an insn into the given buffers and updates 410 1.1 christos the extract info. 411 1.1 christos Returns 0 if all is well, non-zero otherwise. */ 412 1.1 christos 413 1.1 christos static int 414 1.1 christos read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 415 1.1 christos bfd_vma pc, 416 1.1 christos disassemble_info *info, 417 1.1 christos bfd_byte *buf, 418 1.1 christos int buflen, 419 1.1 christos CGEN_EXTRACT_INFO *ex_info, 420 1.1 christos unsigned long *insn_value) 421 1.1 christos { 422 1.1 christos int status = (*info->read_memory_func) (pc, buf, buflen, info); 423 1.1 christos 424 1.1 christos if (status != 0) 425 1.1 christos { 426 1.1 christos (*info->memory_error_func) (status, pc, info); 427 1.1 christos return -1; 428 1.1 christos } 429 1.1 christos 430 1.1 christos ex_info->dis_info = info; 431 1.1 christos ex_info->valid = (1 << buflen) - 1; 432 1.1 christos ex_info->insn_bytes = buf; 433 1.1 christos 434 1.1 christos *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG); 435 1.1 christos return 0; 436 1.1 christos } 437 1.1 christos 438 1.1 christos /* Utility to print an insn. 439 1.1 christos BUF is the base part of the insn, target byte order, BUFLEN bytes long. 440 1.1 christos The result is the size of the insn in bytes or zero for an unknown insn 441 1.1 christos or -1 if an error occurs fetching data (memory_error_func will have 442 1.1 christos been called). */ 443 1.1 christos 444 1.1 christos static int 445 1.1 christos print_insn (CGEN_CPU_DESC cd, 446 1.1 christos bfd_vma pc, 447 1.1 christos disassemble_info *info, 448 1.1 christos bfd_byte *buf, 449 1.1 christos unsigned int buflen) 450 1.1 christos { 451 1.1 christos CGEN_INSN_INT insn_value; 452 1.1 christos const CGEN_INSN_LIST *insn_list; 453 1.1 christos CGEN_EXTRACT_INFO ex_info; 454 1.1.1.7 christos int basesize; 455 1.1 christos 456 1.1 christos /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */ 457 1.1 christos basesize = cd->base_insn_bitsize < buflen * 8 ? 458 1.1 christos cd->base_insn_bitsize : buflen * 8; 459 1.1 christos insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian); 460 1.1 christos 461 1.1 christos 462 1.1 christos /* Fill in ex_info fields like read_insn would. Don't actually call 463 1.1 christos read_insn, since the incoming buffer is already read (and possibly 464 1.1 christos modified a la m32r). */ 465 1.1 christos ex_info.valid = (1 << buflen) - 1; 466 1.1 christos ex_info.dis_info = info; 467 1.1 christos ex_info.insn_bytes = buf; 468 1.1 christos 469 1.1 christos /* The instructions are stored in hash lists. 470 1.1 christos Pick the first one and keep trying until we find the right one. */ 471 1.1 christos 472 1.1 christos insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value); 473 1.1 christos while (insn_list != NULL) 474 1.1 christos { 475 1.1.1.2 christos const CGEN_INSN *insn = insn_list->insn; 476 1.1 christos CGEN_FIELDS fields; 477 1.1 christos int length; 478 1.1 christos unsigned long insn_value_cropped; 479 1.1 christos 480 1.1 christos #ifdef CGEN_VALIDATE_INSN_SUPPORTED 481 1.1 christos /* Not needed as insn shouldn't be in hash lists if not supported. */ 482 1.1 christos /* Supported by this cpu? */ 483 1.1 christos if (! epiphany_cgen_insn_supported (cd, insn)) 484 1.1 christos { 485 1.1 christos insn_list = CGEN_DIS_NEXT_INSN (insn_list); 486 1.1 christos continue; 487 1.1 christos } 488 1.1 christos #endif 489 1.1 christos 490 1.1 christos /* Basic bit mask must be correct. */ 491 1.1 christos /* ??? May wish to allow target to defer this check until the extract 492 1.1 christos handler. */ 493 1.1.1.2 christos 494 1.1 christos /* Base size may exceed this instruction's size. Extract the 495 1.1 christos relevant part from the buffer. */ 496 1.1 christos if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen && 497 1.1 christos (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) 498 1.1 christos insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 499 1.1 christos info->endian == BFD_ENDIAN_BIG); 500 1.1 christos else 501 1.1 christos insn_value_cropped = insn_value; 502 1.1 christos 503 1.1 christos if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn)) 504 1.1 christos == CGEN_INSN_BASE_VALUE (insn)) 505 1.1 christos { 506 1.1 christos /* Printing is handled in two passes. The first pass parses the 507 1.1 christos machine insn and extracts the fields. The second pass prints 508 1.1 christos them. */ 509 1.1 christos 510 1.1 christos /* Make sure the entire insn is loaded into insn_value, if it 511 1.1 christos can fit. */ 512 1.1 christos if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) && 513 1.1 christos (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) 514 1.1 christos { 515 1.1 christos unsigned long full_insn_value; 516 1.1 christos int rc = read_insn (cd, pc, info, buf, 517 1.1 christos CGEN_INSN_BITSIZE (insn) / 8, 518 1.1 christos & ex_info, & full_insn_value); 519 1.1 christos if (rc != 0) 520 1.1 christos return rc; 521 1.1 christos length = CGEN_EXTRACT_FN (cd, insn) 522 1.1 christos (cd, insn, &ex_info, full_insn_value, &fields, pc); 523 1.1 christos } 524 1.1 christos else 525 1.1 christos length = CGEN_EXTRACT_FN (cd, insn) 526 1.1 christos (cd, insn, &ex_info, insn_value_cropped, &fields, pc); 527 1.1 christos 528 1.1 christos /* Length < 0 -> error. */ 529 1.1 christos if (length < 0) 530 1.1 christos return length; 531 1.1 christos if (length > 0) 532 1.1 christos { 533 1.1 christos CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length); 534 1.1 christos /* Length is in bits, result is in bytes. */ 535 1.1 christos return length / 8; 536 1.1 christos } 537 1.1 christos } 538 1.1 christos 539 1.1 christos insn_list = CGEN_DIS_NEXT_INSN (insn_list); 540 1.1 christos } 541 1.1 christos 542 1.1 christos return 0; 543 1.1 christos } 544 1.1 christos 545 1.1 christos /* Default value for CGEN_PRINT_INSN. 546 1.1 christos The result is the size of the insn in bytes or zero for an unknown insn 547 1.1 christos or -1 if an error occured fetching bytes. */ 548 1.1 christos 549 1.1 christos #ifndef CGEN_PRINT_INSN 550 1.1 christos #define CGEN_PRINT_INSN default_print_insn 551 1.1 christos #endif 552 1.1 christos 553 1.1 christos static int 554 1.1 christos default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) 555 1.1 christos { 556 1.1 christos bfd_byte buf[CGEN_MAX_INSN_SIZE]; 557 1.1 christos int buflen; 558 1.1 christos int status; 559 1.1 christos 560 1.1 christos /* Attempt to read the base part of the insn. */ 561 1.1 christos buflen = cd->base_insn_bitsize / 8; 562 1.1 christos status = (*info->read_memory_func) (pc, buf, buflen, info); 563 1.1 christos 564 1.1 christos /* Try again with the minimum part, if min < base. */ 565 1.1 christos if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 566 1.1 christos { 567 1.1 christos buflen = cd->min_insn_bitsize / 8; 568 1.1 christos status = (*info->read_memory_func) (pc, buf, buflen, info); 569 1.1 christos } 570 1.1 christos 571 1.1 christos if (status != 0) 572 1.1 christos { 573 1.1 christos (*info->memory_error_func) (status, pc, info); 574 1.1 christos return -1; 575 1.1 christos } 576 1.1 christos 577 1.1 christos return print_insn (cd, pc, info, buf, buflen); 578 1.1 christos } 579 1.1 christos 580 1.1 christos /* Main entry point. 581 1.1 christos Print one instruction from PC on INFO->STREAM. 582 1.1 christos Return the size of the instruction (in bytes). */ 583 1.1 christos 584 1.1 christos typedef struct cpu_desc_list 585 1.1.1.7 christos { 586 1.1 christos struct cpu_desc_list *next; 587 1.1 christos CGEN_BITSET *isa; 588 1.1 christos int mach; 589 1.1 christos int endian; 590 1.1 christos int insn_endian; 591 1.1 christos CGEN_CPU_DESC cd; 592 1.1 christos } cpu_desc_list; 593 1.1 christos 594 1.1 christos int 595 1.1 christos print_insn_epiphany (bfd_vma pc, disassemble_info *info) 596 1.1 christos { 597 1.1 christos static cpu_desc_list *cd_list = 0; 598 1.1.1.7 christos cpu_desc_list *cl = 0; 599 1.1 christos static CGEN_CPU_DESC cd = 0; 600 1.1 christos static CGEN_BITSET *prev_isa; 601 1.1 christos static int prev_mach; 602 1.1 christos static int prev_endian; 603 1.1 christos static int prev_insn_endian; 604 1.1 christos int length; 605 1.1.1.7 christos CGEN_BITSET *isa; 606 1.1.1.7 christos int mach; 607 1.1.1.7 christos int endian = (info->endian == BFD_ENDIAN_BIG 608 1.1 christos ? CGEN_ENDIAN_BIG 609 1.1 christos : CGEN_ENDIAN_LITTLE); 610 1.1 christos int insn_endian = (info->endian_code == BFD_ENDIAN_BIG 611 1.1 christos ? CGEN_ENDIAN_BIG 612 1.1 christos : CGEN_ENDIAN_LITTLE); 613 1.1 christos enum bfd_architecture arch; 614 1.1 christos 615 1.1 christos /* ??? gdb will set mach but leave the architecture as "unknown" */ 616 1.1 christos #ifndef CGEN_BFD_ARCH 617 1.1.1.2 christos #define CGEN_BFD_ARCH bfd_arch_epiphany 618 1.1 christos #endif 619 1.1 christos arch = info->arch; 620 1.1 christos if (arch == bfd_arch_unknown) 621 1.1 christos arch = CGEN_BFD_ARCH; 622 1.1 christos 623 1.1 christos /* There's no standard way to compute the machine or isa number 624 1.1 christos so we leave it to the target. */ 625 1.1 christos #ifdef CGEN_COMPUTE_MACH 626 1.1 christos mach = CGEN_COMPUTE_MACH (info); 627 1.1 christos #else 628 1.1 christos mach = info->mach; 629 1.1 christos #endif 630 1.1 christos 631 1.1 christos #ifdef CGEN_COMPUTE_ISA 632 1.1 christos { 633 1.1 christos static CGEN_BITSET *permanent_isa; 634 1.1 christos 635 1.1 christos if (!permanent_isa) 636 1.1 christos permanent_isa = cgen_bitset_create (MAX_ISAS); 637 1.1.1.6 christos isa = permanent_isa; 638 1.1 christos cgen_bitset_clear (isa); 639 1.1 christos cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info)); 640 1.1 christos } 641 1.1 christos #else 642 1.1 christos isa = info->private_data; 643 1.1 christos #endif 644 1.1 christos 645 1.1 christos /* If we've switched cpu's, try to find a handle we've used before */ 646 1.1 christos if (cd 647 1.1 christos && (cgen_bitset_compare (isa, prev_isa) != 0 648 1.1 christos || mach != prev_mach 649 1.1 christos || endian != prev_endian)) 650 1.1 christos { 651 1.1 christos cd = 0; 652 1.1 christos for (cl = cd_list; cl; cl = cl->next) 653 1.1 christos { 654 1.1 christos if (cgen_bitset_compare (cl->isa, isa) == 0 && 655 1.1 christos cl->mach == mach && 656 1.1 christos cl->endian == endian) 657 1.1 christos { 658 1.1.1.2 christos cd = cl->cd; 659 1.1 christos prev_isa = cd->isas; 660 1.1 christos break; 661 1.1 christos } 662 1.1 christos } 663 1.1 christos } 664 1.1 christos 665 1.1 christos /* If we haven't initialized yet, initialize the opcode table. */ 666 1.1 christos if (! cd) 667 1.1 christos { 668 1.1 christos const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach); 669 1.1 christos const char *mach_name; 670 1.1 christos 671 1.1 christos if (!arch_type) 672 1.1 christos abort (); 673 1.1.1.7 christos mach_name = arch_type->printable_name; 674 1.1 christos 675 1.1 christos prev_isa = cgen_bitset_copy (isa); 676 1.1 christos prev_mach = mach; 677 1.1.1.7 christos prev_endian = endian; 678 1.1 christos prev_insn_endian = insn_endian; 679 1.1 christos cd = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa, 680 1.1 christos CGEN_CPU_OPEN_BFDMACH, mach_name, 681 1.1 christos CGEN_CPU_OPEN_ENDIAN, prev_endian, 682 1.1 christos CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian, 683 1.1 christos CGEN_CPU_OPEN_END); 684 1.1 christos if (!cd) 685 1.1 christos abort (); 686 1.1 christos 687 1.1 christos /* Save this away for future reference. */ 688 1.1 christos cl = xmalloc (sizeof (struct cpu_desc_list)); 689 1.1 christos cl->cd = cd; 690 1.1 christos cl->isa = prev_isa; 691 1.1 christos cl->mach = mach; 692 1.1 christos cl->endian = endian; 693 1.1 christos cl->next = cd_list; 694 1.1 christos cd_list = cl; 695 1.1 christos 696 1.1 christos epiphany_cgen_init_dis (cd); 697 1.1 christos } 698 1.1 christos 699 1.1 christos /* We try to have as much common code as possible. 700 1.1 christos But at this point some targets need to take over. */ 701 1.1 christos /* ??? Some targets may need a hook elsewhere. Try to avoid this, 702 1.1 christos but if not possible try to move this hook elsewhere rather than 703 1.1 christos have two hooks. */ 704 1.1 christos length = CGEN_PRINT_INSN (cd, pc, info); 705 1.1 christos if (length > 0) 706 1.1 christos return length; 707 1.1 christos if (length < 0) 708 return -1; 709 710 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 711 return cd->default_insn_bitsize / 8; 712 } 713