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