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