4f5bf84aead8ad8af5451ed78bd20dc9ac73d87d
[external/binutils.git] / opcodes / pdp11-dis.c
1 /* Print DEC PDP-11 instructions.
2    Copyright 2001, 2002 Free Software Foundation, Inc.
3
4 This file 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 "sysdep.h"
19 #include "dis-asm.h"
20 #include "opcode/pdp11.h"
21
22 #define AFTER_INSTRUCTION       "\t"
23 #define OPERAND_SEPARATOR       ", "
24
25 #define JUMP    0x1000  /* flag that this operand is used in a jump */
26
27 #define FPRINTF (*info->fprintf_func)
28 #define F       info->stream
29
30 /* sign-extend a 16-bit number in an int */
31 #define SIGN_BITS       (8 * sizeof (int) - 16)
32 #define sign_extend(x) (((x) << SIGN_BITS) >> SIGN_BITS)
33
34 static int read_word PARAMS ((bfd_vma memaddr, int *word,
35                               disassemble_info *info));
36 static void print_signed_octal PARAMS ((int n, disassemble_info *info));
37 static void print_reg PARAMS ((int reg, disassemble_info *info));
38 static void print_freg PARAMS ((int freg, disassemble_info *info));
39 static int print_operand PARAMS ((bfd_vma *memaddr, int code,
40                                   disassemble_info *info));
41 static int print_foperand PARAMS ((bfd_vma *memaddr, int code,
42                                    disassemble_info *info));
43 int print_insn_pdp11 PARAMS ((bfd_vma memaddr, disassemble_info *info));
44
45 static int
46 read_word (memaddr, word, info)
47      bfd_vma memaddr;
48      int *word;
49      disassemble_info *info;
50 {
51   int status;
52   bfd_byte x[2];
53
54   status = (*info->read_memory_func) (memaddr, x, 2, info);
55   if (status != 0)
56     return -1;
57
58   *word = x[1] << 8 | x[0];
59   return 0;
60 }
61
62 static void
63 print_signed_octal (n, info)
64      int n;
65      disassemble_info *info;
66 {
67   if (n < 0)
68     FPRINTF (F, "-%o", -n);
69   else
70     FPRINTF (F, "%o", n);
71 }
72
73 static void
74 print_reg (reg, info)
75      int reg;
76      disassemble_info *info;
77 {
78   /* mask off the addressing mode, if any */
79   reg &= 7;
80
81   switch (reg)
82     {
83     case 0: case 1: case 2: case 3: case 4: case 5:
84                 FPRINTF (F, "r%d", reg); break;
85     case 6:     FPRINTF (F, "sp"); break;
86     case 7:     FPRINTF (F, "pc"); break;
87     default: ;  /* error */
88     }
89 }
90
91 static void
92 print_freg (freg, info)
93      int freg;
94      disassemble_info *info;
95 {
96   FPRINTF (F, "fr%d", freg);
97 }
98
99 static int
100 print_operand (memaddr, code, info)
101      bfd_vma *memaddr;
102      int code;
103      disassemble_info *info;
104 {
105   int mode = (code >> 3) & 7;
106   int reg = code & 7;
107   int disp;
108
109   switch (mode)
110     {
111     case 0:
112       print_reg (reg, info);
113       break;
114     case 1:
115       FPRINTF (F, "(");
116       print_reg (reg, info);
117       FPRINTF (F, ")");
118       break;
119     case 2:
120       if (reg == 7)
121         {
122           int data;
123           if (read_word (*memaddr, &data, info) < 0)
124             return -1;
125           FPRINTF (F, "$");
126           print_signed_octal (sign_extend (data), info);
127           *memaddr += 2;
128         }
129       else
130         {
131           FPRINTF (F, "(");
132           print_reg (reg, info);
133           FPRINTF (F, ")+");
134         }
135         break;
136     case 3:
137       if (reg == 7)
138         {
139           int address;
140           if (read_word (*memaddr, &address, info) < 0)
141             return -1;
142           FPRINTF (F, "*$%o", address);
143           *memaddr += 2;
144         }
145       else
146         {
147           FPRINTF (F, "*(");
148           print_reg (reg, info);
149           FPRINTF (F, ")+");
150         }
151         break;
152     case 4:
153       FPRINTF (F, "-(");
154       print_reg (reg, info);
155       FPRINTF (F, ")");
156       break;
157     case 5:
158       FPRINTF (F, "*-(");
159       print_reg (reg, info);
160       FPRINTF (F, ")");
161       break;
162     case 6:
163     case 7:
164       if (read_word (*memaddr, &disp, info) < 0)
165         return -1;
166       *memaddr += 2;
167       if (reg == 7)
168         {
169           bfd_vma address = *memaddr + sign_extend (disp);
170           if (mode == 7)
171             FPRINTF (F, "*");
172           if (!(code & JUMP))
173             FPRINTF (F, "$");
174           (*info->print_address_func) (address, info);
175         }
176       else
177         {
178           if (mode == 7)
179             FPRINTF (F, "*");
180           print_signed_octal (sign_extend (disp), info);
181           FPRINTF (F, "(");
182           print_reg (reg, info);
183           FPRINTF (F, ")");
184         }
185       break;
186     }
187
188   return 0;
189 }
190
191 static int
192 print_foperand (memaddr, code, info)
193      bfd_vma *memaddr;
194      int code;
195      disassemble_info *info;
196 {
197   int mode = (code >> 3) & 7;
198   int reg = code & 7;
199
200   if (mode == 0)
201     print_freg (reg, info);
202   else
203     return print_operand (memaddr, code, info);
204
205   return 0;
206 }
207
208 /* Print the PDP-11 instruction at address MEMADDR in debugged memory,
209    on INFO->STREAM.  Returns length of the instruction, in bytes.  */
210
211 int
212 print_insn_pdp11 (memaddr, info)
213      bfd_vma memaddr;
214      disassemble_info *info;
215 {
216   bfd_vma start_memaddr = memaddr;
217   int opcode;
218   int src, dst;
219   int i;
220
221   info->bytes_per_line = 6;
222   info->bytes_per_chunk = 2;
223   info->display_endian = BFD_ENDIAN_LITTLE;
224
225   if (read_word (memaddr, &opcode, info) != 0)
226     return -1;
227   memaddr += 2;
228
229   src = (opcode >> 6) & 0x3f;
230   dst = opcode & 0x3f;
231
232   for (i = 0; i < pdp11_num_opcodes; i++)
233     {
234 #define OP pdp11_opcodes[i]
235       if ((opcode & OP.mask) == OP.opcode)
236         switch (OP.type)
237           {
238           case PDP11_OPCODE_NO_OPS:
239             FPRINTF (F, OP.name);
240             goto done;
241           case PDP11_OPCODE_REG:
242             FPRINTF (F, OP.name);
243             FPRINTF (F, AFTER_INSTRUCTION);
244             print_reg (dst, info);
245             goto done;
246           case PDP11_OPCODE_OP:
247             FPRINTF (F, OP.name);
248             FPRINTF (F, AFTER_INSTRUCTION);
249             if (strcmp (OP.name, "jmp") == 0)
250               dst |= JUMP;
251             if (print_operand (&memaddr, dst, info) < 0)
252               return -1;
253             goto done;
254           case PDP11_OPCODE_FOP:
255             FPRINTF (F, OP.name);
256             FPRINTF (F, AFTER_INSTRUCTION);
257             if (strcmp (OP.name, "jmp") == 0)
258               dst |= JUMP;
259             if (print_foperand (&memaddr, dst, info) < 0)
260               return -1;
261             goto done;
262           case PDP11_OPCODE_REG_OP:
263             FPRINTF (F, OP.name);
264             FPRINTF (F, AFTER_INSTRUCTION);
265             print_reg (src, info);
266             FPRINTF (F, OPERAND_SEPARATOR);
267             if (strcmp (OP.name, "jsr") == 0)
268               dst |= JUMP;
269             if (print_operand (&memaddr, dst, info) < 0)
270               return -1;
271             goto done;
272           case PDP11_OPCODE_REG_OP_REV:
273             FPRINTF (F, OP.name);
274             FPRINTF (F, AFTER_INSTRUCTION);
275             if (print_operand (&memaddr, dst, info) < 0)
276               return -1;
277             FPRINTF (F, OPERAND_SEPARATOR);
278             print_reg (src, info);
279             goto done;
280           case PDP11_OPCODE_AC_FOP:
281             {
282               int ac = (opcode & 0xe0) >> 6;
283               FPRINTF (F, OP.name);
284               FPRINTF (F, AFTER_INSTRUCTION);
285               print_freg (ac, info);
286               FPRINTF (F, OPERAND_SEPARATOR);
287               if (print_foperand (&memaddr, dst, info) < 0)
288                 return -1;
289               goto done;
290             }
291           case PDP11_OPCODE_FOP_AC:
292             {
293               int ac = (opcode & 0xe0) >> 6;
294               FPRINTF (F, OP.name);
295               FPRINTF (F, AFTER_INSTRUCTION);
296               if (print_foperand (&memaddr, dst, info) < 0)
297                 return -1;
298               FPRINTF (F, OPERAND_SEPARATOR);
299               print_freg (ac, info);
300               goto done;
301             }
302           case PDP11_OPCODE_AC_OP:
303             {
304               int ac = (opcode & 0xe0) >> 6;
305               FPRINTF (F, OP.name);
306               FPRINTF (F, AFTER_INSTRUCTION);
307               print_freg (ac, info);
308               FPRINTF (F, OPERAND_SEPARATOR);
309               if (print_operand (&memaddr, dst, info) < 0)
310                 return -1;
311               goto done;
312             }
313           case PDP11_OPCODE_OP_AC:
314             {
315               int ac = (opcode & 0xe0) >> 6;
316               FPRINTF (F, OP.name);
317               FPRINTF (F, AFTER_INSTRUCTION);
318               if (print_operand (&memaddr, dst, info) < 0)
319                 return -1;
320               FPRINTF (F, OPERAND_SEPARATOR);
321               print_freg (ac, info);
322               goto done;
323             }
324           case PDP11_OPCODE_OP_OP:
325             FPRINTF (F, OP.name);
326             FPRINTF (F, AFTER_INSTRUCTION);
327             if (print_operand (&memaddr, src, info) < 0)
328               return -1;
329             FPRINTF (F, OPERAND_SEPARATOR);
330             if (print_operand (&memaddr, dst, info) < 0)
331               return -1;
332             goto done;
333           case PDP11_OPCODE_DISPL:
334             {
335               int displ = (opcode & 0xff) << 8;
336               bfd_vma address = memaddr + (sign_extend (displ) >> 7);
337               FPRINTF (F, OP.name);
338               FPRINTF (F, AFTER_INSTRUCTION);
339               (*info->print_address_func) (address, info);
340               goto done;
341             }
342           case PDP11_OPCODE_REG_DISPL:
343             {
344               int displ = (opcode & 0x3f) << 10;
345               bfd_vma address = memaddr + (sign_extend (displ) >> 9);
346               FPRINTF (F, OP.name);
347               FPRINTF (F, AFTER_INSTRUCTION);
348               print_reg (src, info);
349               FPRINTF (F, OPERAND_SEPARATOR);
350               (*info->print_address_func) (address, info);
351               goto done;
352             }
353           case PDP11_OPCODE_IMM8:
354             {
355               int code = opcode & 0xff;
356               FPRINTF (F, OP.name);
357               FPRINTF (F, AFTER_INSTRUCTION);
358               FPRINTF (F, "%o", code);
359               goto done;
360             }
361           case PDP11_OPCODE_IMM6:
362             {
363               int code = opcode & 0x3f;
364               FPRINTF (F, OP.name);
365               FPRINTF (F, AFTER_INSTRUCTION);
366               FPRINTF (F, "%o", code);
367               goto done;
368             }
369           case PDP11_OPCODE_IMM3:
370             {
371               int code = opcode & 7;
372               FPRINTF (F, OP.name);
373               FPRINTF (F, AFTER_INSTRUCTION);
374               FPRINTF (F, "%o", code);
375               goto done;
376             }
377           case PDP11_OPCODE_ILLEGAL:
378             {
379               FPRINTF (F, ".word");
380               FPRINTF (F, AFTER_INSTRUCTION);
381               FPRINTF (F, "%o", opcode);
382               goto done;
383             }
384           default:
385             /* TODO: is this a proper way of signalling an error? */
386             FPRINTF (F, "<internal error: unrecognized instruction type>");
387             return -1;
388           }
389 #undef OP
390     }
391  done:
392
393   return memaddr - start_memaddr;
394 }