1 1.1 skrll /* mmix-dis.c -- Disassemble MMIX instructions. 2 1.1.1.12 christos Copyright (C) 2000-2026 Free Software Foundation, Inc. 3 1.1 skrll Written by Hans-Peter Nilsson (hp (at) bitrange.com) 4 1.1 skrll 5 1.1 skrll This file is part of the GNU opcodes library. 6 1.1 skrll 7 1.1 skrll This library is free software; you can redistribute it and/or modify 8 1.1 skrll it under the terms of the GNU General Public License as published by 9 1.1 skrll the Free Software Foundation; either version 3, or (at your option) 10 1.1 skrll any later version. 11 1.1 skrll 12 1.1 skrll It is distributed in the hope that it will be useful, but WITHOUT 13 1.1 skrll ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 1.1 skrll or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 1.1 skrll License for more details. 16 1.1 skrll 17 1.1 skrll You should have received a copy of the GNU General Public License 18 1.1 skrll along with this file; see the file COPYING. If not, write to the Free 19 1.1 skrll Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 1.1 skrll MA 02110-1301, USA. */ 21 1.1 skrll 22 1.1.1.3 christos #include "sysdep.h" 23 1.1 skrll #include <stdio.h> 24 1.1 skrll #include "opcode/mmix.h" 25 1.1.1.6 christos #include "disassemble.h" 26 1.1 skrll #include "libiberty.h" 27 1.1 skrll #include "bfd.h" 28 1.1 skrll #include "opintl.h" 29 1.1 skrll 30 1.1.1.7 christos #define BAD_CASE(x) \ 31 1.1.1.7 christos do \ 32 1.1.1.7 christos { \ 33 1.1.1.7 christos opcodes_error_handler (_("bad case %d (%s) in %s:%d"), \ 34 1.1.1.7 christos x, #x, __FILE__, __LINE__); \ 35 1.1.1.7 christos abort (); \ 36 1.1.1.7 christos } \ 37 1.1 skrll while (0) 38 1.1 skrll 39 1.1.1.7 christos #define FATAL_DEBUG \ 40 1.1.1.7 christos do \ 41 1.1.1.7 christos { \ 42 1.1.1.7 christos opcodes_error_handler (_("internal: non-debugged code " \ 43 1.1.1.7 christos "(test-case missing): %s:%d"), \ 44 1.1.1.7 christos __FILE__, __LINE__); \ 45 1.1.1.7 christos abort (); \ 46 1.1.1.7 christos } \ 47 1.1 skrll while (0) 48 1.1 skrll 49 1.1 skrll #define ROUND_MODE(n) \ 50 1.1 skrll ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" : \ 51 1.1 skrll (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" : \ 52 1.1 skrll _("(unknown)")) 53 1.1 skrll 54 1.1 skrll #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24) 55 1.1 skrll #define INSN_BACKWARD_OFFSET_BIT (1 << 24) 56 1.1 skrll 57 1.1.1.8 christos #define MAX_REG_NAME_LEN 256 58 1.1.1.8 christos #define MAX_SPEC_REG_NAME_LEN 32 59 1.1 skrll struct mmix_dis_info 60 1.1 skrll { 61 1.1.1.8 christos const char *reg_name[MAX_REG_NAME_LEN]; 62 1.1.1.8 christos const char *spec_reg_name[MAX_SPEC_REG_NAME_LEN]; 63 1.1 skrll 64 1.1 skrll /* Waste a little memory so we don't have to allocate each separately. 65 1.1 skrll We could have an array with static contents for these, but on the 66 1.1 skrll other hand, we don't have to. */ 67 1.1.1.8 christos char basic_reg_name[MAX_REG_NAME_LEN][sizeof ("$255")]; 68 1.1 skrll }; 69 1.1 skrll 70 1.1 skrll /* Initialize a target-specific array in INFO. */ 71 1.1 skrll 72 1.1.1.9 christos static bool 73 1.1 skrll initialize_mmix_dis_info (struct disassemble_info *info) 74 1.1 skrll { 75 1.1 skrll struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info)); 76 1.1.1.2 christos long i; 77 1.1 skrll 78 1.1 skrll if (minfop == NULL) 79 1.1.1.9 christos return false; 80 1.1 skrll 81 1.1 skrll memset (minfop, 0, sizeof (*minfop)); 82 1.1 skrll 83 1.1 skrll /* Initialize register names from register symbols. If there's no 84 1.1 skrll register section, then there are no register symbols. */ 85 1.1 skrll if ((info->section != NULL && info->section->owner != NULL) 86 1.1 skrll || (info->symbols != NULL 87 1.1 skrll && info->symbols[0] != NULL 88 1.1 skrll && bfd_asymbol_bfd (info->symbols[0]) != NULL)) 89 1.1 skrll { 90 1.1 skrll bfd *abfd = info->section && info->section->owner != NULL 91 1.1 skrll ? info->section->owner 92 1.1 skrll : bfd_asymbol_bfd (info->symbols[0]); 93 1.1 skrll asection *reg_section = bfd_get_section_by_name (abfd, "*REG*"); 94 1.1 skrll 95 1.1 skrll if (reg_section != NULL) 96 1.1 skrll { 97 1.1 skrll /* The returned symcount *does* include the ending NULL. */ 98 1.1 skrll long symsize = bfd_get_symtab_upper_bound (abfd); 99 1.1 skrll asymbol **syms = malloc (symsize); 100 1.1 skrll long nsyms; 101 1.1 skrll 102 1.1 skrll if (syms == NULL) 103 1.1 skrll { 104 1.1 skrll FATAL_DEBUG; 105 1.1 skrll free (minfop); 106 1.1.1.9 christos return false; 107 1.1 skrll } 108 1.1 skrll nsyms = bfd_canonicalize_symtab (abfd, syms); 109 1.1 skrll 110 1.1 skrll /* We use the first name for a register. If this is MMO, then 111 1.1 skrll it's the name with the first sequence number, presumably the 112 1.1 skrll first in the source. */ 113 1.1 skrll for (i = 0; i < nsyms && syms[i] != NULL; i++) 114 1.1 skrll { 115 1.1 skrll if (syms[i]->section == reg_section 116 1.1.1.8 christos && syms[i]->value < MAX_REG_NAME_LEN 117 1.1 skrll && minfop->reg_name[syms[i]->value] == NULL) 118 1.1 skrll minfop->reg_name[syms[i]->value] = syms[i]->name; 119 1.1 skrll } 120 1.1.1.11 christos free (syms); 121 1.1 skrll } 122 1.1 skrll } 123 1.1 skrll 124 1.1 skrll /* Fill in the rest with the canonical names. */ 125 1.1.1.8 christos for (i = 0; i < MAX_REG_NAME_LEN; i++) 126 1.1 skrll if (minfop->reg_name[i] == NULL) 127 1.1 skrll { 128 1.1.1.2 christos sprintf (minfop->basic_reg_name[i], "$%ld", i); 129 1.1 skrll minfop->reg_name[i] = minfop->basic_reg_name[i]; 130 1.1 skrll } 131 1.1 skrll 132 1.1 skrll /* We assume it's actually a one-to-one mapping of number-to-name. */ 133 1.1 skrll for (i = 0; mmix_spec_regs[i].name != NULL; i++) 134 1.1 skrll minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name; 135 1.1 skrll 136 1.1 skrll info->private_data = (void *) minfop; 137 1.1.1.9 christos return true; 138 1.1 skrll } 139 1.1 skrll 140 1.1 skrll /* A table indexed by the first byte is constructed as we disassemble each 141 1.1 skrll tetrabyte. The contents is a pointer into mmix_insns reflecting the 142 1.1 skrll first found entry with matching match-bits and lose-bits. Further 143 1.1 skrll entries are considered one after one until the operand constraints 144 1.1 skrll match or the match-bits and lose-bits do not match. Normally a 145 1.1 skrll "further entry" will just show that there was no other match. */ 146 1.1 skrll 147 1.1 skrll static const struct mmix_opcode * 148 1.1 skrll get_opcode (unsigned long insn) 149 1.1 skrll { 150 1.1 skrll static const struct mmix_opcode **opcodes = NULL; 151 1.1 skrll const struct mmix_opcode *opcodep = mmix_opcodes; 152 1.1 skrll unsigned int opcode_part = (insn >> 24) & 255; 153 1.1 skrll 154 1.1 skrll if (opcodes == NULL) 155 1.1 skrll opcodes = xcalloc (256, sizeof (struct mmix_opcode *)); 156 1.1 skrll 157 1.1 skrll opcodep = opcodes[opcode_part]; 158 1.1 skrll if (opcodep == NULL 159 1.1 skrll || (opcodep->match & insn) != opcodep->match 160 1.1 skrll || (opcodep->lose & insn) != 0) 161 1.1 skrll { 162 1.1 skrll /* Search through the table. */ 163 1.1 skrll for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++) 164 1.1 skrll { 165 1.1 skrll /* FIXME: Break out this into an initialization function. */ 166 1.1 skrll if ((opcodep->match & (opcode_part << 24)) == opcode_part 167 1.1 skrll && (opcodep->lose & (opcode_part << 24)) == 0) 168 1.1 skrll opcodes[opcode_part] = opcodep; 169 1.1 skrll 170 1.1 skrll if ((opcodep->match & insn) == opcodep->match 171 1.1 skrll && (opcodep->lose & insn) == 0) 172 1.1 skrll break; 173 1.1 skrll } 174 1.1 skrll } 175 1.1 skrll 176 1.1 skrll if (opcodep->name == NULL) 177 1.1 skrll return NULL; 178 1.1 skrll 179 1.1 skrll /* Check constraints. If they don't match, loop through the next opcode 180 1.1 skrll entries. */ 181 1.1 skrll do 182 1.1 skrll { 183 1.1 skrll switch (opcodep->operands) 184 1.1 skrll { 185 1.1 skrll /* These have no restraint on what can be in the lower three 186 1.1 skrll bytes. */ 187 1.1 skrll case mmix_operands_regs: 188 1.1 skrll case mmix_operands_reg_yz: 189 1.1 skrll case mmix_operands_regs_z_opt: 190 1.1 skrll case mmix_operands_regs_z: 191 1.1 skrll case mmix_operands_jmp: 192 1.1 skrll case mmix_operands_pushgo: 193 1.1 skrll case mmix_operands_pop: 194 1.1 skrll case mmix_operands_sync: 195 1.1 skrll case mmix_operands_x_regs_z: 196 1.1 skrll case mmix_operands_neg: 197 1.1 skrll case mmix_operands_pushj: 198 1.1 skrll case mmix_operands_regaddr: 199 1.1 skrll case mmix_operands_get: 200 1.1 skrll case mmix_operands_set: 201 1.1 skrll case mmix_operands_save: 202 1.1 skrll case mmix_operands_unsave: 203 1.1 skrll case mmix_operands_xyz_opt: 204 1.1 skrll return opcodep; 205 1.1 skrll 206 1.1 skrll /* For a ROUND_MODE, the middle byte must be 0..4. */ 207 1.1 skrll case mmix_operands_roundregs_z: 208 1.1 skrll case mmix_operands_roundregs: 209 1.1 skrll { 210 1.1 skrll int midbyte = (insn >> 8) & 255; 211 1.1 skrll 212 1.1 skrll if (midbyte <= 4) 213 1.1 skrll return opcodep; 214 1.1 skrll } 215 1.1 skrll break; 216 1.1 skrll 217 1.1 skrll case mmix_operands_put: 218 1.1 skrll /* A "PUT". If it is "immediate", then no restrictions, 219 1.1 skrll otherwise we have to make sure the register number is < 32. */ 220 1.1 skrll if ((insn & INSN_IMMEDIATE_BIT) 221 1.1 skrll || ((insn >> 16) & 255) < 32) 222 1.1 skrll return opcodep; 223 1.1 skrll break; 224 1.1 skrll 225 1.1 skrll case mmix_operands_resume: 226 1.1 skrll /* Middle bytes must be zero. */ 227 1.1 skrll if ((insn & 0x00ffff00) == 0) 228 1.1 skrll return opcodep; 229 1.1 skrll break; 230 1.1 skrll 231 1.1 skrll default: 232 1.1 skrll BAD_CASE (opcodep->operands); 233 1.1 skrll } 234 1.1 skrll 235 1.1 skrll opcodep++; 236 1.1 skrll } 237 1.1 skrll while ((opcodep->match & insn) == opcodep->match 238 1.1 skrll && (opcodep->lose & insn) == 0); 239 1.1 skrll 240 1.1 skrll /* If we got here, we had no match. */ 241 1.1 skrll return NULL; 242 1.1 skrll } 243 1.1 skrll 244 1.1.1.8 christos static inline const char * 245 1.1.1.8 christos get_reg_name (const struct mmix_dis_info * minfop, unsigned int x) 246 1.1.1.8 christos { 247 1.1.1.8 christos if (x >= MAX_REG_NAME_LEN) 248 1.1.1.8 christos return _("*illegal*"); 249 1.1.1.8 christos return minfop->reg_name[x]; 250 1.1.1.8 christos } 251 1.1.1.8 christos 252 1.1.1.8 christos static inline const char * 253 1.1.1.8 christos get_spec_reg_name (const struct mmix_dis_info * minfop, unsigned int x) 254 1.1.1.8 christos { 255 1.1.1.8 christos if (x >= MAX_SPEC_REG_NAME_LEN) 256 1.1.1.8 christos return _("*illegal*"); 257 1.1.1.8 christos return minfop->spec_reg_name[x]; 258 1.1.1.8 christos } 259 1.1.1.8 christos 260 1.1 skrll /* The main disassembly function. */ 261 1.1 skrll 262 1.1 skrll int 263 1.1 skrll print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info) 264 1.1 skrll { 265 1.1 skrll unsigned char buffer[4]; 266 1.1 skrll unsigned long insn; 267 1.1 skrll unsigned int x, y, z; 268 1.1 skrll const struct mmix_opcode *opcodep; 269 1.1 skrll int status = (*info->read_memory_func) (memaddr, buffer, 4, info); 270 1.1 skrll struct mmix_dis_info *minfop; 271 1.1 skrll 272 1.1 skrll if (status != 0) 273 1.1 skrll { 274 1.1 skrll (*info->memory_error_func) (status, memaddr, info); 275 1.1 skrll return -1; 276 1.1 skrll } 277 1.1 skrll 278 1.1 skrll /* FIXME: Is -1 suitable? */ 279 1.1 skrll if (info->private_data == NULL 280 1.1 skrll && ! initialize_mmix_dis_info (info)) 281 1.1 skrll return -1; 282 1.1 skrll 283 1.1 skrll minfop = (struct mmix_dis_info *) info->private_data; 284 1.1 skrll x = buffer[1]; 285 1.1 skrll y = buffer[2]; 286 1.1 skrll z = buffer[3]; 287 1.1 skrll 288 1.1 skrll insn = bfd_getb32 (buffer); 289 1.1 skrll 290 1.1 skrll opcodep = get_opcode (insn); 291 1.1 skrll 292 1.1 skrll if (opcodep == NULL) 293 1.1 skrll { 294 1.1 skrll (*info->fprintf_func) (info->stream, _("*unknown*")); 295 1.1 skrll return 4; 296 1.1 skrll } 297 1.1 skrll 298 1.1 skrll (*info->fprintf_func) (info->stream, "%s ", opcodep->name); 299 1.1 skrll 300 1.1 skrll /* Present bytes in the order they are laid out in memory. */ 301 1.1 skrll info->display_endian = BFD_ENDIAN_BIG; 302 1.1 skrll 303 1.1 skrll info->insn_info_valid = 1; 304 1.1 skrll info->bytes_per_chunk = 4; 305 1.1 skrll info->branch_delay_insns = 0; 306 1.1 skrll info->target = 0; 307 1.1 skrll switch (opcodep->type) 308 1.1 skrll { 309 1.1 skrll case mmix_type_normal: 310 1.1 skrll case mmix_type_memaccess_block: 311 1.1 skrll info->insn_type = dis_nonbranch; 312 1.1 skrll break; 313 1.1 skrll 314 1.1 skrll case mmix_type_branch: 315 1.1 skrll info->insn_type = dis_branch; 316 1.1 skrll break; 317 1.1 skrll 318 1.1 skrll case mmix_type_condbranch: 319 1.1 skrll info->insn_type = dis_condbranch; 320 1.1 skrll break; 321 1.1 skrll 322 1.1 skrll case mmix_type_memaccess_octa: 323 1.1 skrll info->insn_type = dis_dref; 324 1.1 skrll info->data_size = 8; 325 1.1 skrll break; 326 1.1 skrll 327 1.1 skrll case mmix_type_memaccess_tetra: 328 1.1 skrll info->insn_type = dis_dref; 329 1.1 skrll info->data_size = 4; 330 1.1 skrll break; 331 1.1 skrll 332 1.1 skrll case mmix_type_memaccess_wyde: 333 1.1 skrll info->insn_type = dis_dref; 334 1.1 skrll info->data_size = 2; 335 1.1 skrll break; 336 1.1 skrll 337 1.1 skrll case mmix_type_memaccess_byte: 338 1.1 skrll info->insn_type = dis_dref; 339 1.1 skrll info->data_size = 1; 340 1.1 skrll break; 341 1.1 skrll 342 1.1 skrll case mmix_type_jsr: 343 1.1 skrll info->insn_type = dis_jsr; 344 1.1 skrll break; 345 1.1 skrll 346 1.1 skrll default: 347 1.1 skrll BAD_CASE(opcodep->type); 348 1.1 skrll } 349 1.1 skrll 350 1.1 skrll switch (opcodep->operands) 351 1.1 skrll { 352 1.1 skrll case mmix_operands_regs: 353 1.1 skrll /* All registers: "$X,$Y,$Z". */ 354 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s,%s", 355 1.1.1.8 christos get_reg_name (minfop, x), 356 1.1.1.8 christos get_reg_name (minfop, y), 357 1.1.1.8 christos get_reg_name (minfop, z)); 358 1.1 skrll break; 359 1.1 skrll 360 1.1 skrll case mmix_operands_reg_yz: 361 1.1 skrll /* Like SETH - "$X,YZ". */ 362 1.1 skrll (*info->fprintf_func) (info->stream, "%s,0x%x", 363 1.1.1.8 christos get_reg_name (minfop, x), y * 256 + z); 364 1.1 skrll break; 365 1.1 skrll 366 1.1 skrll case mmix_operands_regs_z_opt: 367 1.1 skrll case mmix_operands_regs_z: 368 1.1 skrll case mmix_operands_pushgo: 369 1.1 skrll /* The regular "$X,$Y,$Z|Z". */ 370 1.1 skrll if (insn & INSN_IMMEDIATE_BIT) 371 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s,%d", 372 1.1.1.8 christos get_reg_name (minfop, x), 373 1.1.1.8 christos get_reg_name (minfop, y), z); 374 1.1 skrll else 375 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s,%s", 376 1.1.1.8 christos get_reg_name (minfop, x), 377 1.1.1.8 christos get_reg_name (minfop, y), 378 1.1.1.8 christos get_reg_name (minfop, z)); 379 1.1 skrll break; 380 1.1 skrll 381 1.1 skrll case mmix_operands_jmp: 382 1.1 skrll /* Address; only JMP. */ 383 1.1 skrll { 384 1.1 skrll bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4; 385 1.1 skrll 386 1.1 skrll if (insn & INSN_BACKWARD_OFFSET_BIT) 387 1.1 skrll offset -= (256 * 65536) * 4; 388 1.1 skrll 389 1.1 skrll info->target = memaddr + offset; 390 1.1 skrll (*info->print_address_func) (memaddr + offset, info); 391 1.1 skrll } 392 1.1 skrll break; 393 1.1 skrll 394 1.1 skrll case mmix_operands_roundregs_z: 395 1.1 skrll /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z" 396 1.1 skrll "$X,ROUND_MODE,$Z|Z". */ 397 1.1 skrll if (y != 0) 398 1.1 skrll { 399 1.1 skrll if (insn & INSN_IMMEDIATE_BIT) 400 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s,%d", 401 1.1.1.8 christos get_reg_name (minfop, x), 402 1.1 skrll ROUND_MODE (y), z); 403 1.1 skrll else 404 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s,%s", 405 1.1.1.8 christos get_reg_name (minfop, x), 406 1.1 skrll ROUND_MODE (y), 407 1.1.1.8 christos get_reg_name (minfop, z)); 408 1.1 skrll } 409 1.1 skrll else 410 1.1 skrll { 411 1.1 skrll if (insn & INSN_IMMEDIATE_BIT) 412 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%d", 413 1.1.1.8 christos get_reg_name (minfop, x), z); 414 1.1 skrll else 415 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s", 416 1.1.1.8 christos get_reg_name (minfop, x), 417 1.1.1.8 christos get_reg_name (minfop, z)); 418 1.1 skrll } 419 1.1 skrll break; 420 1.1 skrll 421 1.1 skrll case mmix_operands_pop: 422 1.1 skrll /* Like POP - "X,YZ". */ 423 1.1 skrll (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z); 424 1.1 skrll break; 425 1.1 skrll 426 1.1 skrll case mmix_operands_roundregs: 427 1.1 skrll /* Two registers, possibly with rounding: "$X,$Z" or 428 1.1 skrll "$X,ROUND_MODE,$Z". */ 429 1.1 skrll if (y != 0) 430 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s,%s", 431 1.1.1.8 christos get_reg_name (minfop, x), 432 1.1 skrll ROUND_MODE (y), 433 1.1.1.8 christos get_reg_name (minfop, z)); 434 1.1 skrll else 435 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s", 436 1.1.1.8 christos get_reg_name (minfop, x), 437 1.1.1.8 christos get_reg_name (minfop, z)); 438 1.1 skrll break; 439 1.1 skrll 440 1.1 skrll case mmix_operands_sync: 441 1.1 skrll /* Like SYNC - "XYZ". */ 442 1.1 skrll (*info->fprintf_func) (info->stream, "%u", 443 1.1 skrll x * 65536 + y * 256 + z); 444 1.1 skrll break; 445 1.1 skrll 446 1.1 skrll case mmix_operands_x_regs_z: 447 1.1 skrll /* Like SYNCD - "X,$Y,$Z|Z". */ 448 1.1 skrll if (insn & INSN_IMMEDIATE_BIT) 449 1.1 skrll (*info->fprintf_func) (info->stream, "%d,%s,%d", 450 1.1.1.8 christos x, get_reg_name (minfop, y), z); 451 1.1 skrll else 452 1.1 skrll (*info->fprintf_func) (info->stream, "%d,%s,%s", 453 1.1.1.8 christos x, get_reg_name (minfop, y), 454 1.1.1.8 christos get_reg_name (minfop, z)); 455 1.1 skrll break; 456 1.1 skrll 457 1.1 skrll case mmix_operands_neg: 458 1.1 skrll /* Like NEG and NEGU - "$X,Y,$Z|Z". */ 459 1.1 skrll if (insn & INSN_IMMEDIATE_BIT) 460 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%d,%d", 461 1.1.1.8 christos get_reg_name (minfop, x), y, z); 462 1.1 skrll else 463 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%d,%s", 464 1.1.1.8 christos get_reg_name (minfop, x), y, 465 1.1.1.8 christos get_reg_name (minfop, z)); 466 1.1 skrll break; 467 1.1 skrll 468 1.1 skrll case mmix_operands_pushj: 469 1.1 skrll case mmix_operands_regaddr: 470 1.1 skrll /* Like GETA or branches - "$X,Address". */ 471 1.1 skrll { 472 1.1 skrll bfd_signed_vma offset = (y * 256 + z) * 4; 473 1.1 skrll 474 1.1 skrll if (insn & INSN_BACKWARD_OFFSET_BIT) 475 1.1 skrll offset -= 65536 * 4; 476 1.1 skrll 477 1.1 skrll info->target = memaddr + offset; 478 1.1 skrll 479 1.1.1.8 christos (*info->fprintf_func) (info->stream, "%s,", get_reg_name (minfop, x)); 480 1.1 skrll (*info->print_address_func) (memaddr + offset, info); 481 1.1 skrll } 482 1.1 skrll break; 483 1.1 skrll 484 1.1 skrll case mmix_operands_get: 485 1.1 skrll /* GET - "X,spec_reg". */ 486 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s", 487 1.1.1.8 christos get_reg_name (minfop, x), 488 1.1.1.8 christos get_spec_reg_name (minfop, z)); 489 1.1 skrll break; 490 1.1 skrll 491 1.1 skrll case mmix_operands_put: 492 1.1 skrll /* PUT - "spec_reg,$Z|Z". */ 493 1.1 skrll if (insn & INSN_IMMEDIATE_BIT) 494 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%d", 495 1.1.1.8 christos get_spec_reg_name (minfop, x), z); 496 1.1 skrll else 497 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s", 498 1.1.1.8 christos get_spec_reg_name (minfop, x), 499 1.1.1.8 christos get_reg_name (minfop, z)); 500 1.1 skrll break; 501 1.1 skrll 502 1.1 skrll case mmix_operands_set: 503 1.1 skrll /* Two registers, "$X,$Y". */ 504 1.1 skrll (*info->fprintf_func) (info->stream, "%s,%s", 505 1.1.1.8 christos get_reg_name (minfop, x), 506 1.1.1.8 christos get_reg_name (minfop, y)); 507 1.1 skrll break; 508 1.1 skrll 509 1.1 skrll case mmix_operands_save: 510 1.1 skrll /* SAVE - "$X,0". */ 511 1.1 skrll (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]); 512 1.1 skrll break; 513 1.1 skrll 514 1.1 skrll case mmix_operands_unsave: 515 1.1 skrll /* UNSAVE - "0,$Z". */ 516 1.1 skrll (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]); 517 1.1 skrll break; 518 1.1 skrll 519 1.1 skrll case mmix_operands_xyz_opt: 520 1.1 skrll /* Like SWYM or TRAP - "X,Y,Z". */ 521 1.1 skrll (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z); 522 1.1 skrll break; 523 1.1 skrll 524 1.1 skrll case mmix_operands_resume: 525 1.1 skrll /* Just "Z", like RESUME. */ 526 1.1 skrll (*info->fprintf_func) (info->stream, "%d", z); 527 1.1 skrll break; 528 1.1 skrll 529 1.1 skrll default: 530 1.1 skrll (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"), 531 1.1 skrll opcodep->operands); 532 1.1 skrll break; 533 1.1 skrll } 534 1.1 skrll 535 1.1 skrll return 4; 536 1.1 skrll } 537