OSDN Git Service

ATMEL AVR microcontroller support.
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / avr-dis.c
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 "dis-asm.h"
22 #include "opintl.h"
23
24 typedef unsigned char u8;
25 typedef unsigned short u16;
26 typedef unsigned long u32;
27
28 #define IFMASK(a,b)     ((opcode & (a)) == (b))
29 #define CODE_MAX        65537
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 static char* last4[] = {"BLD","BST","SBRC","SBRS"};
42
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 opcode = op & 0x0fff;
151   sprintf(dest, ".%+-8d ; 0x%06X", opcode * 2, pc + 2 + opcode * 2);
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 opcode = (op >> 3) & 0x7f;
164   sprintf(dest, ".%+-8d ; 0x%06X", opcode * 2, pc + 2 + opcode * 2);
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                       {
335                         (*prin) (stream, "    LD      %s,Z+", rd);
336                       }
337                       break;
338                     case 0x2:
339                       {
340                         (*prin) (stream, "    LD      %s,-Z", rd);
341                       }
342                       break;
343                     case 0x9:
344                       {
345                         (*prin) (stream, "    LD      %s,Y+", rd);
346                       }
347                       break;
348                     case 0xa:
349                       {
350                         (*prin) (stream, "    LD      %s,-Y", rd);
351                       }
352                       break;
353                     case 0xc:
354                       {
355                         (*prin) (stream, "    LD      %s,X", rd);
356                       }
357                       break;
358                     case 0xd:
359                       {
360                         (*prin) (stream, "    LD      %s,X+", rd);
361                       }
362                       break;
363                     case 0xe:
364                       {
365                         (*prin) (stream, "    LD      %s,-X", rd);
366                       }
367                       break;
368                     case 0xf:
369                       {
370                         (*prin) (stream, "    POP     %s", rd);
371                       }
372                       break;
373                     default:
374                       {
375                         (*prin) (stream, "    ????");
376                       }
377                       break;
378                     }
379                 }
380                 break;
381               case 0x0200:
382                 {
383                   reg50(opcode, rd);
384                   switch (opcode & 0xf)
385                     {
386                     case 0x0:
387                       {
388                         (*prin) (stream, "    STS     0x%04X,%s",
389                                  avrdis_opcode(addr + 2, info), rd);
390                         cmd_len = 4;
391                       }
392                       break;
393                     case 0x1:
394                       {
395                         (*prin) (stream, "    ST      Z+,%s", rd);
396                       }
397                       break;
398                     case 0x2:
399                       {
400                         (*prin) (stream, "    ST      -Z,%s", rd);
401                       }
402                       break;
403                     case 0x9:
404                       {
405                         (*prin) (stream, "    ST      Y+,%s", rd);
406                       }
407                       break;
408                     case 0xa:
409                       {
410                         (*prin) (stream, "    ST      -Y,%s", rd);
411                       }
412                       break;
413                     case 0xc:
414                       {
415                         (*prin) (stream, "    ST      X,%s", rd);
416                       }
417                       break;
418                     case 0xd:
419                       {
420                         (*prin) (stream, "    ST      X+,%s", rd);
421                       }
422                       break;
423                     case 0xe:
424                       {
425                         (*prin) (stream, "    ST      -X,%s", rd);
426                       }
427                       break;
428                     case 0xf:
429                       {
430                         (*prin) (stream, "    PUSH    %s", rd);
431                       }
432                       break;
433                     default:
434                       {
435                         (*prin) (stream, "    ????");
436                       }
437                       break;
438                     }
439                 }
440                 break;
441               case 0x0400:
442                 {
443                   if (IFMASK(0x020c, 0x000c))
444                     {
445                       u32 k = ((opcode & 0x01f0) >> 3) | (opcode & 1);
446                       k = (k << 16) | avrdis_opcode(addr + 2, info);
447                       if (opcode & 0x0002)
448                         (*prin) (stream, "    CALL    0x%06X", k*2);
449                       else
450                         (*prin) (stream, "    JMP     0x%06X", k*2);
451                       cmd_len = 4;
452                     }
453                   else if (IFMASK(0x010f, 0x0008))
454                     {
455                       int sf = (opcode & 0x70) >> 4;
456                       if (opcode & 0x0080)
457                         (*prin) (stream, "    CL%c", SREG_flags[sf]);
458                       else
459                         (*prin) (stream, "    SE%c", SREG_flags[sf]);
460                     }
461                   else if (IFMASK(0x000f, 0x0009))
462                     {
463                       if (opcode & 0x0100)
464                         (*prin) (stream, "    ICALL");
465                       else
466                         (*prin) (stream, "    IJMP");
467                     }
468                   else if (IFMASK(0x010f, 0x0108))
469                     {
470                       if (IFMASK(0x0090, 0x0000))
471                         (*prin) (stream, "    RET");
472                       else if (IFMASK(0x0090, 0x0010))
473                         (*prin) (stream, "    RETI");
474                       else if (IFMASK(0x00e0, 0x0080))
475                         (*prin) (stream, "    SLEEP");
476                       else if (IFMASK(0x00e0, 0x00a0))
477                         (*prin) (stream, "    WDR");
478                       else if (IFMASK(0x00f0, 0x00c0))
479                         (*prin) (stream, "    LPM");
480                       else if (IFMASK(0x00f0, 0x00d0))
481                         (*prin) (stream, "    ELPM");
482                       else
483                         (*prin) (stream, "    ????");
484                     }
485                   else
486                     {
487                       const char* p;
488                       reg50(opcode, rd);
489                       p = sect94[opcode & 0xf];
490                       if (!p)
491                         p = "????";
492                       (*prin) (stream, "    %-8s%s", p, rd);
493                     }
494                 }
495                 break;
496               case 0x0600:
497                 {
498                   if (opcode & 0x0200)
499                     {
500                       lit204(opcode, rd);
501                       reg20w(opcode, rr);
502                       if (opcode & 0x0100)
503                         (*prin) (stream, "    SBIW    %s,%s", rr, rd);
504                       else
505                         (*prin) (stream, "    ADIW    %s,%s", rr, rd);
506                     }
507                 }
508                 break;
509               case 0x0800:
510               case 0x0a00:
511                 {
512                   (*prin) (stream, "    %-8s0x%02X,%d",
513                            sect98[(opcode & 0x0300) >> 8],
514                            (opcode & 0xf8) >> 3,
515                            opcode & 7);
516                 }
517                 break;
518               default:
519                 {
520                   reg50(opcode, rd);
521                   reg104(opcode, rr);
522                   (*prin) (stream, "    MUL     %s,%s", rd, rr);
523                 }
524               }
525           }
526           break;
527         case 0xb000:
528           {
529             reg50(opcode, rd);
530             regPP(opcode, rr);
531             if (opcode & 0x0800)
532               (*prin) (stream, "    OUT     %s,%s", rr, rd);
533             else
534               (*prin) (stream, "    IN      %s,%s", rd, rr);
535           }
536           break;
537         case 0xc000:
538           {
539             add0fff(opcode, rd, addr);
540             (*prin) (stream, "    RJMP    %s", rd);
541           }
542           break;
543         case 0xd000:
544           {
545             add0fff(opcode, rd, addr);
546             (*prin) (stream, "    RCALL   %s", rd);
547           }
548           break;
549         case 0xe000:
550           {
551             reg40(opcode, rd);
552             lit404(opcode, rr);
553             (*prin) (stream, "    LDI     %s,%s", rd, rr);
554           }
555           break;
556         case 0xf000:
557           {
558             if (opcode & 0x0800)
559               {
560                 reg50(opcode, rd);
561                 (*prin) (stream, "    %-8s%s,%d",
562                          last4[(opcode & 0x0600) >> 9],
563                          rd, opcode & 7);
564               }
565             else
566               {
567                 char* p;
568                 add03f8(opcode, rd, addr);
569                 p = branchs[((opcode & 0x0400) >> 7) | (opcode & 7)];
570                 (*prin) (stream, "    %-8s%s", p, rd);
571               }
572           }
573           break;
574         }
575     }
576   return cmd_len;
577 }