1 /* Disassemble V850 instructions. 2 Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003 3 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 18 19 20 #include <stdio.h> 21 22 #include "sysdep.h" 23 #include "opcode/v850.h" 24 #include "dis-asm.h" 25 #include "opintl.h" 26 27 static const char *const v850_reg_names[] = 28 { "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7", 29 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 30 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 31 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" }; 32 33 static const char *const v850_sreg_names[] = 34 { "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7", 35 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15", 36 "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23", 37 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31", 38 "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23", 39 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" }; 40 41 static const char *const v850_cc_names[] = 42 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le", 43 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" }; 44 45 static int disassemble 46 PARAMS ((bfd_vma, struct disassemble_info *, unsigned long)); 47 48 static int 49 disassemble (memaddr, info, insn) 50 bfd_vma memaddr; 51 struct disassemble_info *info; 52 unsigned long insn; 53 { 54 struct v850_opcode *op = (struct v850_opcode *)v850_opcodes; 55 const struct v850_operand *operand; 56 int match = 0; 57 int short_op = ((insn & 0x0600) != 0x0600); 58 int bytes_read; 59 int target_processor; 60 61 /* Special case: 32 bit MOV */ 62 if ((insn & 0xffe0) == 0x0620) 63 short_op = 1; 64 65 bytes_read = short_op ? 2 : 4; 66 67 /* If this is a two byte insn, then mask off the high bits. */ 68 if (short_op) 69 insn &= 0xffff; 70 71 switch (info->mach) 72 { 73 case 0: 74 default: 75 target_processor = PROCESSOR_V850; 76 break; 77 78 case bfd_mach_v850e: 79 target_processor = PROCESSOR_V850E; 80 break; 81 82 case bfd_mach_v850e1: 83 target_processor = PROCESSOR_V850E1; 84 break; 85 } 86 87 /* Find the opcode. */ 88 while (op->name) 89 { 90 if ((op->mask & insn) == op->opcode 91 && (op->processors & target_processor)) 92 { 93 const unsigned char *opindex_ptr; 94 unsigned int opnum; 95 unsigned int memop; 96 97 match = 1; 98 (*info->fprintf_func) (info->stream, "%s\t", op->name); 99 /*fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );*/ 100 101 memop = op->memop; 102 /* Now print the operands. 103 104 MEMOP is the operand number at which a memory 105 address specification starts, or zero if this 106 instruction has no memory addresses. 107 108 A memory address is always two arguments. 109 110 This information allows us to determine when to 111 insert commas into the output stream as well as 112 when to insert disp[reg] expressions onto the 113 output stream. */ 114 115 for (opindex_ptr = op->operands, opnum = 1; 116 *opindex_ptr != 0; 117 opindex_ptr++, opnum++) 118 { 119 long value; 120 int flag; 121 int status; 122 bfd_byte buffer[4]; 123 124 operand = &v850_operands[*opindex_ptr]; 125 126 if (operand->extract) 127 value = (operand->extract) (insn, 0); 128 else 129 { 130 if (operand->bits == -1) 131 value = (insn & operand->shift); 132 else 133 value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 134 135 if (operand->flags & V850_OPERAND_SIGNED) 136 value = ((long)(value << (32 - operand->bits)) 137 >> (32 - operand->bits)); 138 } 139 140 /* The first operand is always output without any 141 special handling. 142 143 For the following arguments: 144 145 If memop && opnum == memop + 1, then we need '[' since 146 we're about to output the register used in a memory 147 reference. 148 149 If memop && opnum == memop + 2, then we need ']' since 150 we just finished the register in a memory reference. We 151 also need a ',' before this operand. 152 153 Else we just need a comma. 154 155 We may need to output a trailing ']' if the last operand 156 in an instruction is the register for a memory address. 157 158 The exception (and there's always an exception) is the 159 "jmp" insn which needs square brackets around it's only 160 register argument. */ 161 162 if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "["); 163 else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],"); 164 else if (memop == 1 && opnum == 1 165 && (operand->flags & V850_OPERAND_REG)) 166 info->fprintf_func (info->stream, "["); 167 else if (opnum > 1) info->fprintf_func (info->stream, ", "); 168 169 /* extract the flags, ignorng ones which do not effect disassembly output. */ 170 flag = operand->flags; 171 flag &= ~ V850_OPERAND_SIGNED; 172 flag &= ~ V850_OPERAND_RELAX; 173 flag &= - flag; 174 175 switch (flag) 176 { 177 case V850_OPERAND_REG: info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break; 178 case V850_OPERAND_SRG: info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break; 179 case V850_OPERAND_CC: info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break; 180 case V850_OPERAND_EP: info->fprintf_func (info->stream, "ep"); break; 181 default: info->fprintf_func (info->stream, "%d", value); break; 182 case V850_OPERAND_DISP: 183 { 184 bfd_vma addr = value + memaddr; 185 186 /* On the v850 the top 8 bits of an address are used by an overlay manager. 187 Thus it may happen that when we are looking for a symbol to match 188 against an address with some of its top bits set, the search fails to 189 turn up an exact match. In this case we try to find an exact match 190 against a symbol in the lower address space, and if we find one, we 191 use that address. We only do this for JARL instructions however, as 192 we do not want to misinterpret branch instructions. */ 193 if (operand->bits == 22) 194 { 195 if ( ! info->symbol_at_address_func (addr, info) 196 && ((addr & 0xFF000000) != 0) 197 && info->symbol_at_address_func (addr & 0x00FFFFFF, info)) 198 { 199 addr &= 0x00FFFFFF; 200 } 201 } 202 info->print_address_func (addr, info); 203 break; 204 } 205 206 case V850E_PUSH_POP: 207 { 208 static int list12_regs[32] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; 209 static int list18_h_regs[32] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; 210 static int list18_l_regs[32] = { 3, 2, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 14, 15, 13, 12, 7, 6, 5, 4, 11, 10, 9, 8 }; 211 int *regs; 212 int i; 213 unsigned long int mask = 0; 214 int pc = 0; 215 int sr = 0; 216 217 218 switch (operand->shift) 219 { 220 case 0xffe00001: regs = list12_regs; break; 221 case 0xfff8000f: regs = list18_h_regs; break; 222 case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break; /* Do not include magic bit */ 223 default: 224 /* xgettext:c-format */ 225 fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift ); 226 abort(); 227 } 228 229 for (i = 0; i < 32; i++) 230 { 231 if (value & (1 << i)) 232 { 233 switch (regs[ i ]) 234 { 235 default: mask |= (1 << regs[ i ]); break; 236 /* xgettext:c-format */ 237 case 0: fprintf (stderr, _("unknown pop reg: %d\n"), i ); abort(); 238 case -1: pc = 1; break; 239 case -2: sr = 1; break; 240 } 241 } 242 } 243 244 info->fprintf_func (info->stream, "{"); 245 246 if (mask || pc || sr) 247 { 248 if (mask) 249 { 250 unsigned int bit; 251 int shown_one = 0; 252 253 for (bit = 0; bit < 32; bit++) 254 if (mask & (1 << bit)) 255 { 256 unsigned long int first = bit; 257 unsigned long int last; 258 259 if (shown_one) 260 info->fprintf_func (info->stream, ", "); 261 else 262 shown_one = 1; 263 264 info->fprintf_func (info->stream, v850_reg_names[first]); 265 266 for (bit++; bit < 32; bit++) 267 if ((mask & (1 << bit)) == 0) 268 break; 269 270 last = bit; 271 272 if (last > first + 1) 273 { 274 info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]); 275 } 276 } 277 } 278 279 if (pc) 280 info->fprintf_func (info->stream, "%sPC", mask ? ", " : ""); 281 if (sr) 282 info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : ""); 283 } 284 285 info->fprintf_func (info->stream, "}"); 286 } 287 break; 288 289 case V850E_IMMEDIATE16: 290 status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info); 291 if (status == 0) 292 { 293 bytes_read += 2; 294 value = bfd_getl16 (buffer); 295 296 /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16. */ 297 if ((insn & 0x001fffc0) == 0x00130780) 298 value <<= 16; 299 300 info->fprintf_func (info->stream, "0x%x", value); 301 } 302 else 303 { 304 info->memory_error_func (status, memaddr + bytes_read, info); 305 } 306 break; 307 308 case V850E_IMMEDIATE32: 309 status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info); 310 if (status == 0) 311 { 312 bytes_read += 4; 313 value = bfd_getl32 (buffer); 314 info->fprintf_func (info->stream, "0x%lx", value); 315 } 316 else 317 { 318 info->memory_error_func (status, memaddr + bytes_read, info); 319 } 320 break; 321 } 322 323 /* Handle jmp correctly. */ 324 if (memop == 1 && opnum == 1 325 && ((operand->flags & V850_OPERAND_REG) != 0)) 326 (*info->fprintf_func) (info->stream, "]"); 327 } 328 329 /* Close any square bracket we left open. */ 330 if (memop && opnum == memop + 2) 331 (*info->fprintf_func) (info->stream, "]"); 332 333 /* All done. */ 334 break; 335 } 336 op++; 337 } 338 339 if (!match) 340 { 341 if (short_op) 342 info->fprintf_func (info->stream, ".short\t0x%04x", insn); 343 else 344 info->fprintf_func (info->stream, ".long\t0x%08x", insn); 345 } 346 347 return bytes_read; 348 } 349 350 int 351 print_insn_v850 (memaddr, info) 352 bfd_vma memaddr; 353 struct disassemble_info * info; 354 { 355 int status; 356 bfd_byte buffer[4]; 357 unsigned long insn = 0; 358 359 /* First figure out how big the opcode is. */ 360 361 status = info->read_memory_func (memaddr, buffer, 2, info); 362 if (status == 0) 363 { 364 insn = bfd_getl16 (buffer); 365 366 if ( (insn & 0x0600) == 0x0600 367 && (insn & 0xffe0) != 0x0620) 368 { 369 /* If this is a 4 byte insn, read 4 bytes of stuff. */ 370 status = info->read_memory_func (memaddr, buffer, 4, info); 371 372 if (status == 0) 373 insn = bfd_getl32 (buffer); 374 } 375 } 376 377 if (status != 0) 378 { 379 info->memory_error_func (status, memaddr, info); 380 return -1; 381 } 382 383 /* Make sure we tell our caller how many bytes we consumed. */ 384 return disassemble (memaddr, info, insn); 385 } 386