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