1 /* Disassemble AVR instructions. 2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 3 4 Contributed by Denis Chertykov <denisc@overta.ru> 5 6 This program 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 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20 21 #include "sysdep.h" 22 #include "dis-asm.h" 23 #include "opintl.h" 24 25 typedef unsigned char u8; 26 typedef unsigned short u16; 27 typedef unsigned long u32; 28 29 #define IFMASK(a,b) ((opcode & (a)) == (b)) 30 31 static char* SREG_flags = "CZNVSHTI"; 32 static char* sect94[] = {"COM","NEG","SWAP","INC","NULL","ASR","LSR","ROR", 33 0,0,"DEC",0,0,0,0,0}; 34 static char* sect98[] = {"CBI","SBIC","SBI","SBIS"}; 35 static char* branchs[] = { 36 "BRCS","BREQ","BRMI","BRVS", 37 "BRLT","BRHS","BRTS","BRIE", 38 "BRCC","BRNE","BRPL","BRVC", 39 "BRGE","BRHC","BRTC","BRID" 40 }; 41 42 static char* last4[] = {"BLD","BST","SBRC","SBRS"}; 43 44 45 static void dispLDD PARAMS ((u16, char *)); 46 47 static void 48 dispLDD (opcode, dest) 49 u16 opcode; 50 char *dest; 51 { 52 opcode = (((opcode & 0x2000) >> 8) | ((opcode & 0x0c00) >> 7) 53 | (opcode & 7)); 54 sprintf(dest, "%d", opcode); 55 } 56 57 58 static void regPP PARAMS ((u16, char *)); 59 60 static void 61 regPP (opcode, dest) 62 u16 opcode; 63 char *dest; 64 { 65 opcode = ((opcode & 0x0600) >> 5) | (opcode & 0xf); 66 sprintf(dest, "0x%02X", opcode); 67 } 68 69 70 static void reg50 PARAMS ((u16, char *)); 71 72 static void 73 reg50 (opcode, dest) 74 u16 opcode; 75 char *dest; 76 { 77 opcode = (opcode & 0x01f0) >> 4; 78 sprintf(dest, "R%d", opcode); 79 } 80 81 82 static void reg104 PARAMS ((u16, char *)); 83 84 static void 85 reg104 (opcode, dest) 86 u16 opcode; 87 char *dest; 88 { 89 opcode = (opcode & 0xf) | ((opcode & 0x0200) >> 5); 90 sprintf(dest, "R%d", opcode); 91 } 92 93 94 static void reg40 PARAMS ((u16, char *)); 95 96 static void 97 reg40 (opcode, dest) 98 u16 opcode; 99 char *dest; 100 { 101 opcode = (opcode & 0xf0) >> 4; 102 sprintf(dest, "R%d", opcode + 16); 103 } 104 105 106 static void reg20w PARAMS ((u16, char *)); 107 108 static void 109 reg20w (opcode, dest) 110 u16 opcode; 111 char *dest; 112 { 113 opcode = (opcode & 0x30) >> 4; 114 sprintf(dest, "R%d", 24 + opcode * 2); 115 } 116 117 118 static void lit404 PARAMS ((u16, char *)); 119 120 static void 121 lit404 (opcode, dest) 122 u16 opcode; 123 char *dest; 124 { 125 opcode = ((opcode & 0xf00) >> 4) | (opcode & 0xf); 126 sprintf(dest, "0x%02X", opcode); 127 } 128 129 130 static void lit204 PARAMS ((u16, char *)); 131 132 static void 133 lit204 (opcode, dest) 134 u16 opcode; 135 char *dest; 136 { 137 opcode = ((opcode & 0xc0) >> 2) | (opcode & 0xf); 138 sprintf(dest, "0x%02X", opcode); 139 } 140 141 142 static void add0fff PARAMS ((u16, char *, int)); 143 144 static void 145 add0fff (op, dest, pc) 146 u16 op; 147 char *dest; 148 int pc; 149 { 150 int rel_addr = (((op & 0xfff) ^ 0x800) - 0x800) * 2; 151 sprintf(dest, ".%+-8d ; 0x%06X", rel_addr, pc + 2 + rel_addr); 152 } 153 154 155 static void add03f8 PARAMS ((u16, char *, int)); 156 157 static void 158 add03f8 (op, dest, pc) 159 u16 op; 160 char *dest; 161 int pc; 162 { 163 int rel_addr = ((((op >> 3) & 0x7f) ^ 0x40) - 0x40) * 2; 164 sprintf(dest, ".%+-8d ; 0x%06X", rel_addr, pc + 2 + rel_addr); 165 } 166 167 168 static u16 avrdis_opcode PARAMS ((bfd_vma, disassemble_info *)); 169 170 static u16 171 avrdis_opcode (addr, info) 172 bfd_vma addr; 173 disassemble_info *info; 174 { 175 bfd_byte buffer[2]; 176 int status; 177 status = info->read_memory_func(addr, buffer, 2, info); 178 if (status != 0) 179 { 180 info->memory_error_func(status, addr, info); 181 return -1; 182 } 183 return bfd_getl16 (buffer); 184 } 185 186 187 int 188 print_insn_avr(addr, info) 189 bfd_vma addr; 190 disassemble_info *info; 191 { 192 char rr[200]; 193 char rd[200]; 194 u16 opcode; 195 void *stream = info->stream; 196 fprintf_ftype prin = info->fprintf_func; 197 int cmd_len = 2; 198 199 opcode = avrdis_opcode (addr, info); 200 201 if (IFMASK(0xd000, 0x8000)) 202 { 203 char letter; 204 reg50(opcode, rd); 205 dispLDD(opcode, rr); 206 if (opcode & 8) 207 letter = 'Y'; 208 else 209 letter = 'Z'; 210 if (opcode & 0x0200) 211 (*prin) (stream, " STD %c+%s,%s", letter, rr, rd); 212 else 213 (*prin) (stream, " LDD %s,%c+%s", rd, letter, rr); 214 } 215 else 216 { 217 switch (opcode & 0xf000) 218 { 219 case 0x0000: 220 { 221 reg50(opcode, rd); 222 reg104(opcode, rr); 223 switch (opcode & 0x0c00) 224 { 225 case 0x0000: 226 (*prin) (stream, " NOP"); 227 break; 228 case 0x0400: 229 (*prin) (stream, " CPC %s,%s", rd, rr); 230 break; 231 case 0x0800: 232 (*prin) (stream, " SBC %s,%s", rd, rr); 233 break; 234 case 0x0c00: 235 (*prin) (stream, " ADD %s,%s", rd, rr); 236 break; 237 } 238 } 239 break; 240 case 0x1000: 241 { 242 reg50(opcode, rd); 243 reg104(opcode, rr); 244 switch (opcode & 0x0c00) 245 { 246 case 0x0000: 247 (*prin) (stream, " CPSE %s,%s", rd, rr); 248 break; 249 case 0x0400: 250 (*prin) (stream, " CP %s,%s", rd, rr); 251 break; 252 case 0x0800: 253 (*prin) (stream, " SUB %s,%s", rd, rr); 254 break; 255 case 0x0c00: 256 (*prin) (stream, " ADC %s,%s", rd, rr); 257 break; 258 } 259 } 260 break; 261 case 0x2000: 262 { 263 reg50(opcode, rd); 264 reg104(opcode, rr); 265 switch (opcode & 0x0c00) 266 { 267 case 0x0000: 268 (*prin) (stream, " AND %s,%s", rd, rr); 269 break; 270 case 0x0400: 271 (*prin) (stream, " EOR %s,%s", rd, rr); 272 break; 273 case 0x0800: 274 (*prin) (stream, " OR %s,%s", rd, rr); 275 break; 276 case 0x0c00: 277 (*prin) (stream, " MOV %s,%s", rd, rr); 278 break; 279 } 280 } 281 break; 282 case 0x3000: 283 { 284 reg40(opcode, rd); 285 lit404(opcode, rr); 286 (*prin) (stream, " CPI %s,%s", rd, rr); 287 } 288 break; 289 case 0x4000: 290 { 291 reg40(opcode, rd); 292 lit404(opcode, rr); 293 (*prin) (stream, " SBCI %s,%s", rd, rr); 294 } 295 break; 296 case 0x5000: 297 { 298 reg40(opcode, rd); 299 lit404(opcode, rr); 300 (*prin) (stream, " SUBI %s,%s", rd, rr); 301 } 302 break; 303 case 0x6000: 304 { 305 reg40(opcode, rd); 306 lit404(opcode, rr); 307 (*prin) (stream, " ORI %s,%s", rd, rr); 308 } 309 break; 310 case 0x7000: 311 { 312 reg40(opcode, rd); 313 lit404(opcode, rr); 314 (*prin) (stream, " ANDI %s,%s", rd, rr); 315 } 316 break; 317 case 0x9000: 318 { 319 switch (opcode & 0x0e00) 320 { 321 case 0x0000: 322 { 323 reg50(opcode, rd); 324 switch (opcode & 0xf) 325 { 326 case 0x0: 327 { 328 (*prin) (stream, " LDS %s,0x%04X", rd, 329 avrdis_opcode(addr + 2, info)); 330 cmd_len = 4; 331 } 332 break; 333 case 0x1: 334 (*prin) (stream, " LD %s,Z+", rd); 335 break; 336 case 0x2: 337 (*prin) (stream, " LD %s,-Z", rd); 338 break; 339 case 0x9: 340 (*prin) (stream, " LD %s,Y+", rd); 341 break; 342 case 0xa: 343 (*prin) (stream, " LD %s,-Y", rd); 344 break; 345 case 0xc: 346 (*prin) (stream, " LD %s,X", rd); 347 break; 348 case 0xd: 349 (*prin) (stream, " LD %s,X+", rd); 350 break; 351 case 0xe: 352 (*prin) (stream, " LD %s,-X", rd); 353 break; 354 case 0xf: 355 (*prin) (stream, " POP %s", rd); 356 break; 357 default: 358 (*prin) (stream, " ????"); 359 break; 360 } 361 } 362 break; 363 case 0x0200: 364 { 365 reg50(opcode, rd); 366 switch (opcode & 0xf) 367 { 368 case 0x0: 369 { 370 (*prin) (stream, " STS 0x%04X,%s", 371 avrdis_opcode(addr + 2, info), rd); 372 cmd_len = 4; 373 } 374 break; 375 case 0x1: 376 (*prin) (stream, " ST Z+,%s", rd); 377 break; 378 case 0x2: 379 (*prin) (stream, " ST -Z,%s", rd); 380 break; 381 case 0x9: 382 (*prin) (stream, " ST Y+,%s", rd); 383 break; 384 case 0xa: 385 (*prin) (stream, " ST -Y,%s", rd); 386 break; 387 case 0xc: 388 (*prin) (stream, " ST X,%s", rd); 389 break; 390 case 0xd: 391 (*prin) (stream, " ST X+,%s", rd); 392 break; 393 case 0xe: 394 (*prin) (stream, " ST -X,%s", rd); 395 break; 396 case 0xf: 397 (*prin) (stream, " PUSH %s", rd); 398 break; 399 default: 400 (*prin) (stream, " ????"); 401 break; 402 } 403 } 404 break; 405 case 0x0400: 406 { 407 if (IFMASK(0x020c, 0x000c)) 408 { 409 u32 k = ((opcode & 0x01f0) >> 3) | (opcode & 1); 410 k = (k << 16) | avrdis_opcode(addr + 2, info); 411 if (opcode & 0x0002) 412 (*prin) (stream, " CALL 0x%06X", k*2); 413 else 414 (*prin) (stream, " JMP 0x%06X", k*2); 415 cmd_len = 4; 416 } 417 else if (IFMASK(0x010f, 0x0008)) 418 { 419 int sf = (opcode & 0x70) >> 4; 420 if (opcode & 0x0080) 421 (*prin) (stream, " CL%c", SREG_flags[sf]); 422 else 423 (*prin) (stream, " SE%c", SREG_flags[sf]); 424 } 425 else if (IFMASK(0x000f, 0x0009)) 426 { 427 if (opcode & 0x0100) 428 (*prin) (stream, " ICALL"); 429 else 430 (*prin) (stream, " IJMP"); 431 } 432 else if (IFMASK(0x010f, 0x0108)) 433 { 434 if (IFMASK(0x0090, 0x0000)) 435 (*prin) (stream, " RET"); 436 else if (IFMASK(0x0090, 0x0010)) 437 (*prin) (stream, " RETI"); 438 else if (IFMASK(0x00e0, 0x0080)) 439 (*prin) (stream, " SLEEP"); 440 else if (IFMASK(0x00e0, 0x00a0)) 441 (*prin) (stream, " WDR"); 442 else if (IFMASK(0x00f0, 0x00c0)) 443 (*prin) (stream, " LPM"); 444 else if (IFMASK(0x00f0, 0x00d0)) 445 (*prin) (stream, " ELPM"); 446 else 447 (*prin) (stream, " ????"); 448 } 449 else 450 { 451 const char* p; 452 reg50(opcode, rd); 453 p = sect94[opcode & 0xf]; 454 if (!p) 455 p = "????"; 456 (*prin) (stream, " %-8s%s", p, rd); 457 } 458 } 459 break; 460 case 0x0600: 461 { 462 if (opcode & 0x0200) 463 { 464 lit204(opcode, rd); 465 reg20w(opcode, rr); 466 if (opcode & 0x0100) 467 (*prin) (stream, " SBIW %s,%s", rr, rd); 468 else 469 (*prin) (stream, " ADIW %s,%s", rr, rd); 470 } 471 } 472 break; 473 case 0x0800: 474 case 0x0a00: 475 { 476 (*prin) (stream, " %-8s0x%02X,%d", 477 sect98[(opcode & 0x0300) >> 8], 478 (opcode & 0xf8) >> 3, 479 opcode & 7); 480 } 481 break; 482 default: 483 { 484 reg50(opcode, rd); 485 reg104(opcode, rr); 486 (*prin) (stream, " MUL %s,%s", rd, rr); 487 } 488 } 489 } 490 break; 491 case 0xb000: 492 { 493 reg50(opcode, rd); 494 regPP(opcode, rr); 495 if (opcode & 0x0800) 496 (*prin) (stream, " OUT %s,%s", rr, rd); 497 else 498 (*prin) (stream, " IN %s,%s", rd, rr); 499 } 500 break; 501 case 0xc000: 502 { 503 add0fff(opcode, rd, addr); 504 (*prin) (stream, " RJMP %s", rd); 505 } 506 break; 507 case 0xd000: 508 { 509 add0fff(opcode, rd, addr); 510 (*prin) (stream, " RCALL %s", rd); 511 } 512 break; 513 case 0xe000: 514 { 515 reg40(opcode, rd); 516 lit404(opcode, rr); 517 (*prin) (stream, " LDI %s,%s", rd, rr); 518 } 519 break; 520 case 0xf000: 521 { 522 if (opcode & 0x0800) 523 { 524 reg50(opcode, rd); 525 (*prin) (stream, " %-8s%s,%d", 526 last4[(opcode & 0x0600) >> 9], 527 rd, opcode & 7); 528 } 529 else 530 { 531 char* p; 532 add03f8(opcode, rd, addr); 533 p = branchs[((opcode & 0x0400) >> 7) | (opcode & 7)]; 534 (*prin) (stream, " %-8s%s", p, rd); 535 } 536 } 537 break; 538 } 539 } 540 return cmd_len; 541 } 542