1 /* Disassemble D10V instructions. 2 Copyright (C) 1996-2014 Free Software Foundation, Inc. 3 4 This file is part of the GNU opcodes library. 5 6 This library is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 It is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 14 License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 #include "sysdep.h" 22 #include <stdio.h> 23 #include "opcode/d10v.h" 24 #include "dis-asm.h" 25 26 /* The PC wraps at 18 bits, except for the segment number, 27 so use this mask to keep the parts we want. */ 28 #define PC_MASK 0x0303FFFF 29 30 static void 31 print_operand (struct d10v_operand *oper, 32 unsigned long insn, 33 struct d10v_opcode *op, 34 bfd_vma memaddr, 35 struct disassemble_info *info) 36 { 37 int num, shift; 38 39 if (oper->flags == OPERAND_ATMINUS) 40 { 41 (*info->fprintf_func) (info->stream, "@-"); 42 return; 43 } 44 if (oper->flags == OPERAND_MINUS) 45 { 46 (*info->fprintf_func) (info->stream, "-"); 47 return; 48 } 49 if (oper->flags == OPERAND_PLUS) 50 { 51 (*info->fprintf_func) (info->stream, "+"); 52 return; 53 } 54 if (oper->flags == OPERAND_ATSIGN) 55 { 56 (*info->fprintf_func) (info->stream, "@"); 57 return; 58 } 59 if (oper->flags == OPERAND_ATPAR) 60 { 61 (*info->fprintf_func) (info->stream, "@("); 62 return; 63 } 64 65 shift = oper->shift; 66 67 /* The LONG_L format shifts registers over by 15. */ 68 if (op->format == LONG_L && (oper->flags & OPERAND_REG)) 69 shift += 15; 70 71 num = (insn >> shift) & (0x7FFFFFFF >> (31 - oper->bits)); 72 73 if (oper->flags & OPERAND_REG) 74 { 75 int i; 76 int match = 0; 77 78 num += (oper->flags 79 & (OPERAND_GPR | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL)); 80 if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1)) 81 num += num ? OPERAND_ACC1 : OPERAND_ACC0; 82 for (i = 0; i < d10v_reg_name_cnt (); i++) 83 { 84 if (num == (d10v_predefined_registers[i].value & ~ OPERAND_SP)) 85 { 86 if (d10v_predefined_registers[i].pname) 87 (*info->fprintf_func) (info->stream, "%s", 88 d10v_predefined_registers[i].pname); 89 else 90 (*info->fprintf_func) (info->stream, "%s", 91 d10v_predefined_registers[i].name); 92 match = 1; 93 break; 94 } 95 } 96 if (match == 0) 97 { 98 /* This would only get executed if a register was not in the 99 register table. */ 100 if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1)) 101 (*info->fprintf_func) (info->stream, "a"); 102 else if (oper->flags & OPERAND_CONTROL) 103 (*info->fprintf_func) (info->stream, "cr"); 104 else if (oper->flags & OPERAND_REG) 105 (*info->fprintf_func) (info->stream, "r"); 106 (*info->fprintf_func) (info->stream, "%d", num & REGISTER_MASK); 107 } 108 } 109 else 110 { 111 /* Addresses are right-shifted by 2. */ 112 if (oper->flags & OPERAND_ADDR) 113 { 114 long max; 115 int neg = 0; 116 117 max = (1 << (oper->bits - 1)); 118 if (num & max) 119 { 120 num = -num & ((1 << oper->bits) - 1); 121 neg = 1; 122 } 123 num = num << 2; 124 if (info->flags & INSN_HAS_RELOC) 125 (*info->print_address_func) (num & PC_MASK, info); 126 else 127 { 128 if (neg) 129 (*info->print_address_func) ((memaddr - num) & PC_MASK, info); 130 else 131 (*info->print_address_func) ((memaddr + num) & PC_MASK, info); 132 } 133 } 134 else 135 { 136 if (oper->flags & OPERAND_SIGNED) 137 { 138 int max = (1 << (oper->bits - 1)); 139 if (num & max) 140 { 141 num = -num & ((1 << oper->bits) - 1); 142 (*info->fprintf_func) (info->stream, "-"); 143 } 144 } 145 (*info->fprintf_func) (info->stream, "0x%x", num); 146 } 147 } 148 } 149 150 static void 151 dis_long (unsigned long insn, 152 bfd_vma memaddr, 153 struct disassemble_info *info) 154 { 155 int i; 156 struct d10v_opcode *op = (struct d10v_opcode *) d10v_opcodes; 157 struct d10v_operand *oper; 158 int need_paren = 0; 159 int match = 0; 160 161 while (op->name) 162 { 163 if ((op->format & LONG_OPCODE) 164 && ((op->mask & insn) == (unsigned long) op->opcode)) 165 { 166 match = 1; 167 (*info->fprintf_func) (info->stream, "%s\t", op->name); 168 169 for (i = 0; op->operands[i]; i++) 170 { 171 oper = (struct d10v_operand *) &d10v_operands[op->operands[i]]; 172 if (oper->flags == OPERAND_ATPAR) 173 need_paren = 1; 174 print_operand (oper, insn, op, memaddr, info); 175 if (op->operands[i + 1] && oper->bits 176 && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS 177 && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS) 178 (*info->fprintf_func) (info->stream, ", "); 179 } 180 break; 181 } 182 op++; 183 } 184 185 if (!match) 186 (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn); 187 188 if (need_paren) 189 (*info->fprintf_func) (info->stream, ")"); 190 } 191 192 static void 193 dis_2_short (unsigned long insn, 194 bfd_vma memaddr, 195 struct disassemble_info *info, 196 int order) 197 { 198 int i, j; 199 unsigned int ins[2]; 200 struct d10v_opcode *op; 201 int match, num_match = 0; 202 struct d10v_operand *oper; 203 int need_paren = 0; 204 205 ins[0] = (insn & 0x3FFFFFFF) >> 15; 206 ins[1] = insn & 0x00007FFF; 207 208 for (j = 0; j < 2; j++) 209 { 210 op = (struct d10v_opcode *) d10v_opcodes; 211 match = 0; 212 while (op->name) 213 { 214 if ((op->format & SHORT_OPCODE) 215 && ((((unsigned int) op->mask) & ins[j]) 216 == (unsigned int) op->opcode)) 217 { 218 (*info->fprintf_func) (info->stream, "%s\t", op->name); 219 for (i = 0; op->operands[i]; i++) 220 { 221 oper = (struct d10v_operand *) &d10v_operands[op->operands[i]]; 222 if (oper->flags == OPERAND_ATPAR) 223 need_paren = 1; 224 print_operand (oper, ins[j], op, memaddr, info); 225 if (op->operands[i + 1] && oper->bits 226 && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS 227 && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS) 228 (*info->fprintf_func) (info->stream, ", "); 229 } 230 match = 1; 231 num_match++; 232 break; 233 } 234 op++; 235 } 236 if (!match) 237 (*info->fprintf_func) (info->stream, "unknown"); 238 239 switch (order) 240 { 241 case 0: 242 (*info->fprintf_func) (info->stream, "\t->\t"); 243 order = -1; 244 break; 245 case 1: 246 (*info->fprintf_func) (info->stream, "\t<-\t"); 247 order = -1; 248 break; 249 case 2: 250 (*info->fprintf_func) (info->stream, "\t||\t"); 251 order = -1; 252 break; 253 default: 254 break; 255 } 256 } 257 258 if (num_match == 0) 259 (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn); 260 261 if (need_paren) 262 (*info->fprintf_func) (info->stream, ")"); 263 } 264 265 int 266 print_insn_d10v (bfd_vma memaddr, struct disassemble_info *info) 267 { 268 int status; 269 bfd_byte buffer[4]; 270 unsigned long insn; 271 272 status = (*info->read_memory_func) (memaddr, buffer, 4, info); 273 if (status != 0) 274 { 275 (*info->memory_error_func) (status, memaddr, info); 276 return -1; 277 } 278 insn = bfd_getb32 (buffer); 279 280 status = insn & FM11; 281 switch (status) 282 { 283 case 0: 284 dis_2_short (insn, memaddr, info, 2); 285 break; 286 case FM01: 287 dis_2_short (insn, memaddr, info, 0); 288 break; 289 case FM10: 290 dis_2_short (insn, memaddr, info, 1); 291 break; 292 case FM11: 293 dis_long (insn, memaddr, info); 294 break; 295 } 296 return 4; 297 } 298