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