1 /* Print TI TMS320C80 (MVP) instructions 2 Copyright 1996, 1997, 1998, 2000 Free Software Foundation, Inc. 3 4 This file is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17 18 #include <stdio.h> 19 20 #include "sysdep.h" 21 #include "opcode/tic80.h" 22 #include "dis-asm.h" 23 24 static int length; 25 26 static void print_operand_bitnum PARAMS ((struct disassemble_info *, long)); 27 static void print_operand_condition_code PARAMS ((struct disassemble_info *, long)); 28 static void print_operand_control_register PARAMS ((struct disassemble_info *, long)); 29 static void print_operand_float PARAMS ((struct disassemble_info *, long)); 30 static void print_operand_integer PARAMS ((struct disassemble_info *, long)); 31 static void print_operand PARAMS ((struct disassemble_info *, long, unsigned long, 32 const struct tic80_operand *, bfd_vma)); 33 static int print_one_instruction PARAMS ((struct disassemble_info *, bfd_vma, 34 unsigned long, const struct tic80_opcode *)); 35 static int print_instruction PARAMS ((struct disassemble_info *, bfd_vma, unsigned long, 36 const struct tic80_opcode *)); 37 static int fill_instruction PARAMS ((struct disassemble_info *, bfd_vma, 38 unsigned long *)); 39 40 /* Print an integer operand. Try to be somewhat smart about the 41 format by assuming that small positive or negative integers are 42 probably loop increment values, structure offsets, or similar 43 values that are more meaningful printed as signed decimal values. 44 Larger numbers are probably better printed as hex values. */ 45 46 static void 47 print_operand_integer (info, value) 48 struct disassemble_info *info; 49 long value; 50 { 51 if ((value > 9999 || value < -9999)) 52 { 53 (*info->fprintf_func) (info->stream, "%#lx", value); 54 } 55 else 56 { 57 (*info->fprintf_func) (info->stream, "%ld", value); 58 } 59 } 60 61 /* FIXME: depends upon sizeof (long) == sizeof (float) and 62 also upon host floating point format matching target 63 floating point format. */ 64 65 static void 66 print_operand_float (info, value) 67 struct disassemble_info *info; 68 long value; 69 { 70 union { float f; long l; } fval; 71 72 fval.l = value; 73 (*info->fprintf_func) (info->stream, "%g", fval.f); 74 } 75 76 static void 77 print_operand_control_register (info, value) 78 struct disassemble_info *info; 79 long value; 80 { 81 const char *tmp; 82 83 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR); 84 if (tmp != NULL) 85 { 86 (*info->fprintf_func) (info->stream, "%s", tmp); 87 } 88 else 89 { 90 (*info->fprintf_func) (info->stream, "%#lx", value); 91 } 92 } 93 94 static void 95 print_operand_condition_code (info, value) 96 struct disassemble_info *info; 97 long value; 98 { 99 const char *tmp; 100 101 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC); 102 if (tmp != NULL) 103 { 104 (*info->fprintf_func) (info->stream, "%s", tmp); 105 } 106 else 107 { 108 (*info->fprintf_func) (info->stream, "%ld", value); 109 } 110 } 111 112 static void 113 print_operand_bitnum (info, value) 114 struct disassemble_info *info; 115 long value; 116 { 117 int bitnum; 118 const char *tmp; 119 120 bitnum = ~value & 0x1F; 121 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM); 122 if (tmp != NULL) 123 { 124 (*info->fprintf_func) (info->stream, "%s", tmp); 125 } 126 else 127 { 128 (*info->fprintf_func) (info->stream, "%ld", bitnum); 129 } 130 } 131 132 /* Print the operand as directed by the flags. */ 133 134 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17))) 135 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15))) 136 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11))) 137 138 static void 139 print_operand (info, value, insn, operand, memaddr) 140 struct disassemble_info *info; 141 long value; 142 unsigned long insn; 143 const struct tic80_operand *operand; 144 bfd_vma memaddr; 145 { 146 if ((operand->flags & TIC80_OPERAND_GPR) != 0) 147 { 148 (*info->fprintf_func) (info->stream, "r%ld", value); 149 if (M_SI (insn, operand) || M_LI (insn, operand)) 150 { 151 (*info->fprintf_func) (info->stream, ":m"); 152 } 153 } 154 else if ((operand->flags & TIC80_OPERAND_FPA) != 0) 155 { 156 (*info->fprintf_func) (info->stream, "a%ld", value); 157 } 158 else if ((operand->flags & TIC80_OPERAND_PCREL) != 0) 159 { 160 (*info->print_address_func) (memaddr + 4 * value, info); 161 } 162 else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0) 163 { 164 (*info->print_address_func) (value, info); 165 } 166 else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0) 167 { 168 print_operand_bitnum (info, value); 169 } 170 else if ((operand->flags & TIC80_OPERAND_CC) != 0) 171 { 172 print_operand_condition_code (info, value); 173 } 174 else if ((operand->flags & TIC80_OPERAND_CR) != 0) 175 { 176 print_operand_control_register (info, value); 177 } 178 else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0) 179 { 180 print_operand_float (info, value); 181 } 182 else if ((operand->flags & TIC80_OPERAND_BITFIELD)) 183 { 184 (*info->fprintf_func) (info->stream, "%#lx", value); 185 } 186 else 187 { 188 print_operand_integer (info, value); 189 } 190 191 /* If this is a scaled operand, then print the modifier. */ 192 193 if (R_SCALED (insn, operand)) 194 { 195 (*info->fprintf_func) (info->stream, ":s"); 196 } 197 } 198 199 /* We have chosen an opcode table entry. */ 200 201 static int 202 print_one_instruction (info, memaddr, insn, opcode) 203 struct disassemble_info *info; 204 bfd_vma memaddr; 205 unsigned long insn; 206 const struct tic80_opcode *opcode; 207 { 208 const struct tic80_operand *operand; 209 long value; 210 int status; 211 const unsigned char *opindex; 212 int close_paren; 213 214 (*info->fprintf_func) (info->stream, "%-10s", opcode->name); 215 216 for (opindex = opcode->operands; *opindex != 0; opindex++) 217 { 218 operand = tic80_operands + *opindex; 219 220 /* Extract the value from the instruction. */ 221 if (operand->extract) 222 { 223 value = (*operand->extract) (insn, (int *) NULL); 224 } 225 else if (operand->bits == 32) 226 { 227 status = fill_instruction (info, memaddr, (unsigned long *) &value); 228 if (status == -1) 229 { 230 return (status); 231 } 232 } 233 else 234 { 235 value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 236 if ((operand->flags & TIC80_OPERAND_SIGNED) != 0 237 && (value & (1 << (operand->bits - 1))) != 0) 238 { 239 value -= 1 << operand->bits; 240 } 241 } 242 243 /* If this operand is enclosed in parenthesis, then print 244 the open paren, otherwise just print the regular comma 245 separator, except for the first operand. */ 246 247 if ((operand->flags & TIC80_OPERAND_PARENS) == 0) 248 { 249 close_paren = 0; 250 if (opindex != opcode->operands) 251 { 252 (*info->fprintf_func) (info->stream, ","); 253 } 254 } 255 else 256 { 257 close_paren = 1; 258 (*info->fprintf_func) (info->stream, "("); 259 } 260 261 print_operand (info, value, insn, operand, memaddr); 262 263 /* If we printed an open paren before printing this operand, close 264 it now. The flag gets reset on each loop. */ 265 266 if (close_paren) 267 { 268 (*info->fprintf_func) (info->stream, ")"); 269 } 270 } 271 return (length); 272 } 273 274 /* There are no specific bits that tell us for certain whether a vector 275 instruction opcode contains one or two instructions. However since 276 a destination register of r0 is illegal, we can check for nonzero 277 values in both destination register fields. Only opcodes that have 278 two valid instructions will have non-zero in both. */ 279 280 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0)) 281 282 static int 283 print_instruction (info, memaddr, insn, vec_opcode) 284 struct disassemble_info *info; 285 bfd_vma memaddr; 286 unsigned long insn; 287 const struct tic80_opcode *vec_opcode; 288 { 289 const struct tic80_opcode *opcode; 290 const struct tic80_opcode *opcode_end; 291 292 /* Find the first opcode match in the opcodes table. For vector 293 opcodes (vec_opcode != NULL) find the first match that is not the 294 previously found match. FIXME: there should be faster ways to 295 search (hash table or binary search), but don't worry too much 296 about it until other TIc80 support is finished. */ 297 298 opcode_end = tic80_opcodes + tic80_num_opcodes; 299 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++) 300 { 301 if ((insn & opcode->mask) == opcode->opcode && 302 opcode != vec_opcode) 303 { 304 break; 305 } 306 } 307 308 if (opcode == opcode_end) 309 { 310 /* No match found, just print the bits as a .word directive. */ 311 (*info->fprintf_func) (info->stream, ".word %#08lx", insn); 312 } 313 else 314 { 315 /* Match found, decode the instruction. */ 316 length = print_one_instruction (info, memaddr, insn, opcode); 317 if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn)) 318 { 319 /* There is another instruction to print from the same opcode. 320 Print the separator and then find and print the other 321 instruction. */ 322 (*info->fprintf_func) (info->stream, " || "); 323 length = print_instruction (info, memaddr, insn, opcode); 324 } 325 } 326 return (length); 327 } 328 329 /* Get the next 32 bit word from the instruction stream and convert it 330 into internal format in the unsigned long INSN, for which we are 331 passed the address. Return 0 on success, -1 on error. */ 332 333 static int 334 fill_instruction (info, memaddr, insnp) 335 struct disassemble_info *info; 336 bfd_vma memaddr; 337 unsigned long *insnp; 338 { 339 bfd_byte buffer[4]; 340 int status; 341 342 /* Get the bits for the next 32 bit word and put in buffer. */ 343 344 status = (*info->read_memory_func) (memaddr + length, buffer, 4, info); 345 if (status != 0) 346 { 347 (*info->memory_error_func) (status, memaddr, info); 348 return (-1); 349 } 350 351 /* Read was successful, so increment count of bytes read and convert 352 the bits into internal format. */ 353 354 length += 4; 355 if (info->endian == BFD_ENDIAN_LITTLE) 356 { 357 *insnp = bfd_getl32 (buffer); 358 } 359 else if (info->endian == BFD_ENDIAN_BIG) 360 { 361 *insnp = bfd_getb32 (buffer); 362 } 363 else 364 { 365 /* FIXME: Should probably just default to one or the other. */ 366 abort (); 367 } 368 return (0); 369 } 370 371 int 372 print_insn_tic80 (memaddr, info) 373 bfd_vma memaddr; 374 struct disassemble_info *info; 375 { 376 unsigned long insn; 377 int status; 378 379 length = 0; 380 info->bytes_per_line = 8; 381 status = fill_instruction (info, memaddr, &insn); 382 if (status != -1) 383 { 384 status = print_instruction (info, memaddr, insn, NULL); 385 } 386 return (status); 387 } 388