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